문제 링크
요약
- 누적합을 생각하면 된다.
최종
결과
- 누적합으로 풀어주면 된다.
i부터j까지의 합 (0 <= i <= j < n) 을SUM[i,j]라고 하자. 이 문제는 모든i,j에 대해SUM[i,j]의 최대값을 찾는 문제다.SUM[i,j]는 누적합으로 바꾸면SUM[0,j] - SUM[0,i-1]가 된다.- 일단
0 <= j < n인 어떤j에 대해 이 값이 최대가 되게 하려면0 <= i <= j모든i에 대해SUM[0,i-1]가 최소가 되어야 한다.-1 <= i - 1 <= j - 1이므로 이 값을MINSUM[-1,j-1]라고 하자.- 즉,
MINSUM[-1,j-1]은SUM[0,-1], SUM[0,0], SUM[0,1], ..., SUM[0,j-1]값들의 최소값이다. 이때SUM[0,-1]은 ‘아무것도 누적되지 않은 상태’ 이므로 덧셈의 항등원인 0이다.
- 즉,
- 정리하면
0 <= j < n인 어떤j에 대한 최대값은SUM[0,j] - MINSUM[-1,j-1]이라고 말할 수 있다. 따라서 문제의 정답은 모든j에 대한SUM[0,j] - MINSUM[-1,j-1]값들의 최대값이다.
- 이걸 기준으로 아래 코드를 보자.
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int cur_acc_sum = 0;
int max_sub_sum = -10001;
int min_acc_sum = 0;
for (int num : nums) {
cur_acc_sum += num;
max_sub_sum = max(max_sub_sum, cur_acc_sum - min_acc_sum);
min_acc_sum = min(min_acc_sum, cur_acc_sum);
}
return max_sub_sum;
}
};- 위에서 설명한 것을 이 코드와 접목시켜보면 다음과 같다.
- 우선 변수 설명:
cur_acc_sum은SUM[0,j]이다. 이놈의 초기값은 (현재는 아무것도 누적되지 않은 상태이기 때문에) 덧셈의 항등원인 0이다.min_acc_sum은MINSUM[-1,j-1]이다. 위에서 말한대로SUM[0,-1]은 덧셈의 항등원인 0이므로 이 값도 0으로 초기화된다.max_sum_sum은0 <= x <= j범위의 모든x에 대한SUM[0,x] - MINSUM[-1,x-1]값들의 최대값 이다.
- 이때 loop 에서 뭐하는지를 보자.
L9:cur_acc_sum에num을 누적한다. 즉,SUM[0,j] = SUM[0,j-1] + nums[j]를 수행한 셈이다.L10를 보기 전에, 우선L11부터 보자. 여기서는min_acc_sum을 업데이트한다.- 지금까지는
min_acc_sum이MINSUM[-1,j-1]였다. 이것은SUM[0,-1], ..., SUM[0,j-1]들의 최소값이다. 따라서MINSUM[-1,j-1]와SUM[0,j]중 최소값으로min_acc_sum을 업데이트해주면 이때min_acc_sum이MINSUM[-1,j]가 된다.
- 지금까지는
L10에서는max_sum_sum을 업데이트한다.- 위에서 말한 대로
L11에서min_acc_sum이MINSUM[-1,j]가 된다. 그렇다는건L10에서는 아직min_acc_sum이MINSUM[-1,j-1]이다.- 이 말은,
L10과L11의 순서를 바꾸면 안된다 는 것이다. max_sum_sum의 업데이트는 반드시min_acc_sum의 업데이트 이전에 수행되어야 한다.
- 이 말은,
- 따라서
cur_acc_sum - min_acc_sum은SUM[0,j] - MIN[-1,j-1]와 같다. 이 값과 기존의max_acc_sum을 비교해 더 큰 값으로 업데이트해준다.
- 위에서 말한 대로
- 우선 변수 설명:
