1편 링크: http://gall.dcinside.com/board/view/?id=programming&no=725837
이 문제는 사실 매우 유명한 동적계획법 문제인 "Maximum Contiguous Subarray Sum" 문제와 결국 본질적으로 같은 문제이다.
어떤 한 점을 기준으로 그 왼쪽에서 최소 합을 갖는 연속된 부분배열을 고르고, 오른쪽에서는 최대 합을 갖는 연속된 부분배열을 고르거나,
반대로 오른쪽에서 최소합, 왼쪽에서 최대합을 구하는 것을 반복하면 필요한 모든 경우를 볼 수 있다(해당 기준점을 옮겨가면서 모든 경우를 확인하면 된다).
포인트는 기준점이 이동했을 때, 배열 전체를 순회하지 않고 미리 계산해둔 값을 이용하는 것이다.
이는 동적계획법으로 어떤 점 "까지의" 최대/최소 부분배열의 합, 어떤 점 "부터의" 최대/최소 부분배열의 합을 가지고 있는 것으로 간단히 해결할 수 있다.
N = 배열의 길이라고 하면
Additional Space Complexity는 O(N)
Time Complexity도 O(N)이 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | unsigned distance(int x, int y) { if (min(x, y) >= 0 || max(x, y) < 0) { return unsigned(max(x, y) - min(x, y)); } else { return unsigned(max(x, y)) + unsigned(-min(x, y)); } } unsigned find_maximum_absdiff(const vector<int>& array) { vector<int>::size_type n = array.size(); vector<vector<int>::size_type> indexes(n-1); iota(indexes.begin(), indexes.end(), 1); vector<int> max_subarray_until(n, array[0]); vector<int> min_subarray_until(n, array[0]); for (const auto& i: indexes) { max_subarray_until[i] = max({array[i], max_subarray_until[i-1] + array[i]}); min_subarray_until[i] = min({array[i], min_subarray_until[i-1] + array[i]}); } vector<vector<int>::size_type> indexes_reversed(n-1); iota(indexes_reversed.rbegin(), indexes_reversed.rend(), 0); vector<int> max_subarray_from(n, array[n-1]); vector<int> min_subarray_from(n, array[n-1]); for (const auto& i: indexes_reversed) { max_subarray_from[i] = max({array[i], max_subarray_from[i+1] + array[i]}); min_subarray_from[i] = min({array[i], min_subarray_from[i+1] + array[i]}); } unsigned answer = 0; for (const auto& i: indexes) { answer = max({answer, distance(min_subarray_until[i-1], max_subarray_from[i]), distance(max_subarray_until[i-1], min_subarray_from[i])}); } return answer; } | cs |
연습문제1) Additional Space Complexity를 O(1)로 줄일 수 있을까요? 있다면, 어떻게 짜면 될까요?
댓글 0