-
Kadane's Algorithm(카다네 알고리즘) SubArray 최대합 구하기Algorithm 2020. 12. 29. 23:15
Maximum subarray problem이라는 문제가 있다
N개의 원소를 가진 배열이 있을 때, (i,j)의 연속되는 인덱스를 선택했을 때의 원소 최대 합을 구하는 문제이다
즉 [4, -2, 5, -4, 3, -7, -6, 10, 5]라는 배열이 있을 때 maximum subarray problem의 답은 7~8번째 원소값을 더한 15가 된다.
이 때 가능한 해결법은 약 세가지가 있다
1️⃣ 모든 인덱스 (i, j)에 대해 sum을 계산한 뒤 maximum값을 구한다
for(int i=0;i<n;i++) for (int j = i; j < n; j++) { int sum = 0; for (int k = i; k <= j; k++) sum += arr[k]; if (sum > maxSum)maxSum = sum; }
이 경우는 떠올리기도, 구현도 간편하지만 O(N^3)이라는 극악의 시간복잡도를 자랑한다
2️⃣ 1번과 유사하지만, 앞에서 구한 sub sum값을 활용
for (int i = 0; i < n; i++) { int sum = 0; for (int j = i; j < n; j++) { sum += arr[j]; if (sum > maxSum)maxSum = sum; } }
구간합을 구하기 위해 앞에서 구한 값을 활용해줬다.
(i,j)의 구간 합 = (i,j-1)의 구간 합 + (j)의 원소 값인 점을 이용한다.
하지만 이 경우에도 시간복잡도는 O(N^2)이며, N이 10000을 넘어가면 for문을 1억번 도는 사태가 발생한다
3️⃣ Kadane's Algorithm
카다네(카데인) 알고리즘이라고 한다
Dynamic Programming을 사용하는 알고리즘이면서, 시간복잡도를 O(N)에 해결 가능한 효율적인 알고리즘이다
DP알고리즘(카다네 알고리즘)을 적용해서 Maximum Subarray Problem을 해결하는 법
1. Subproblem&Recursion
2번에서 적용했던 방법처럼, 이전에 구했던 subarray의 값을 활용한다.
현재 인덱스를 i라고 할 때, (0,i)까지에서 subarray의 최대 부분합은
(0,i-1)까지의 subarray의 부분합을 연장할지 or (i,~)로 시작하는 부분합을 시작할지 결정하면 된다.
2. Memoization
i번째 subarray의 최대 부분합을 구할 때, i-1번째 subarray의 최대 부분합을 여러 번 구하는 것을 방지하기 위해 배열에 [(0,i)까지의 배열에서 maximum subarray값]을 저장한다.
따라서, i번째 subproblem의 값은 i-1번째 subproblem의 값에 dependent하다.
그렇기 때문에 0번째 array의 값부터 차례대로 구한다.
위와 같은 경우에서는, 중간에 -4가 끼어있어도 3+4+(-4)+6+5 = 14가 정답이다(-4일 때, -4보다 3+4+(-4)가 더 크기 때문에 후자를 택한다).
3. Code
maxSum = dp[0] = arr[0]; for (int i = 1; i < n; i++) { dp[i] = max(dp[i - 1] + arr[i], arr[i]); if (dp[i] > maxSum) maxSum=dp[i]; }
4. Time Complexity
단순 연산의 시간복잡도는 O(1)이기 때문에, 반복 크기는 입력 size에 비례한다.
따라서 해당 알고리즘의 시간복잡도는 O(N)이다
카다네 알고리즘을 적용해서 풀 수 있는 문제
'Algorithm' 카테고리의 다른 글
Quick Select를 O(n)에 구현 가능한 Median of Medians 알고리즘 (0) 2021.01.03 Array의 k번째 작은 element 찾기 - QuickSelect 알고리즘 (0) 2021.01.01 시간복잡도 Big-O(빅 오) 표기법 (0) 2020.12.30 Divide-and-Conquer 알고리즘과 Master Theorem (0) 2020.09.29 Quick Sort 정의, 알고리즘 및 코드에 대해 (0) 2020.05.13