문제 링크: https://leetcode.com/problems/minimum-size-subarray-sum/
nums 배열에서 총합이 target 이상이면서 그 중 길이가 최소인 SubArray를 찾는다.
입력
출력
여러 가지 방안을 생각해보다가, 도저히 좋은 아이디어가 떠오르지 않아서 결국 무식한 방법을 써보기로 했다.
Sliding Window
기법을 사용해 모든 경우를 다 탐색하는 방법을 선택했다.
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int right, sum;
int answer = 1000000;
for (int num : nums) {
if (num >= target)
return 1;
}
for (int left = 0; left < nums.length - 1; left++) {
sum = nums[left];
right = left;
while (right < nums.length -1) {
sum += nums[right+1];
right++;
if (target <= sum) {
answer = Math.min(right - left + 1, answer);
}
}
}
return answer == 1000000 ? 0 : answer;
}
}
아래 사진과 같은 방식으로 진행되는 코드이다.
하지만 18번째 케이스에서 시간초과가 발생해 실패했다..!
public int minSubArrayLen(int target, int[] nums) {
int sum = 0, from = 0, win = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
while (sum >= target) {
win = Math.min(win, i - from + 1);
sum -= nums[from++];
}
}
return (win == Integer.MAX_VALUE) ? 0 : win;
}
i = 3일 때의 과정을 그림으로 나타내면 아래와 같다.
2 + 3 + 1 + 2 까지 더했을 때, sum이 8이 되므로 sum ≥ target 조건에 성립되어, while문으로 실행하게 된다.
오른쪽 그림처럼 while문을 실행하는데, 첫 번째 요소 값을 빼면 바로 sum ≥ target 조건에 성립되지 않아,while문을 빠져나오게 된다.
나와 비슷하면서도 다른 점은 window의 크기를 자유자재로 바꾸면서 탐색했다는 점이다.
위의 그림에서도 보면, while문에서 sum의 값이 target보다 작아지자, 그 window를 유지한채 다음 요소까지 window 크기를 늘려가며 탐색했다는 것이다.
내 풀이 같은 경우는 어찌보면 계속 중복해서 계산하는 구간이 너무 많았지만, 이 풀이를 이용하면 계산했던 구간은 다시 재사용한다는 점으로, 시간복잡도를 O(n)으로 감소시켰다.
이런 부분합에 관련된 문제는 항상 직접적으로 구한다기 보다, 부분합의 부분합을 이용하거나, 아니면 전체에서 감소시켜가며, 부분합을 찾는 아이디어가 대부분인 것 같다.
이번 문제에서는 아무래도 부분합 “최대”를 찾아야 하는 문제이므로, 전체의 합에서 감소시켜나가는 아이디어가 문제의 핵심이었다고 생각한다.