diff --git a/Python3/53. Maximum Subarray.md b/Python3/53. Maximum Subarray.md new file mode 100644 index 0000000..1a9d770 --- /dev/null +++ b/Python3/53. Maximum Subarray.md @@ -0,0 +1,88 @@ +## Step 1. Initial Solution + +- パッと思いついたのは累積和を使う方法 + - prefix_sumを複数管理しておく必要はあまりなさそう + - 一つの変数で管理しておいて、マイナスになるなら捨ててしまう + - これで一旦実装してみたが、答えがマイナスになる場合を想定していなくてマイナスの場合にcontinueしてしまっていた + - continueせずにmaxの更新を行うように変更してギリギリ10分くらい + +```python +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + max_sum = nums[0] + prefix_sum = 0 + for num in nums: + prefix_sum += num + if prefix_sum < 0: + prefix_sum = 0 + continue + max_sum = max(max_sum, prefix_sum) + return max_sum +``` + +### Complexity Analysis + +- 時間計算量:O(n) +- 空間計算量:O(1) + +## Step 2. Alternatives + +- LeetCodeのFollow upに書いてある分割統治法でやろうとしてみたがよく分からなかったので撤退 + - こういう書き方があるらしい + + ```python + class Solution: + def maxSubArray(self, nums: List[int]) -> int: + prefix_sums = [*nums] + suffix_sums = [*nums] + for i in range(1, len(nums)): + if prefix_sums[i-1] > 0: + prefix_sums[i] += prefix_sums[i-1] + for i in range(len(nums)-2, -1, -1): + if suffix_sums[i+1] > 0: + suffix_sums[i] += suffix_sums[i+1] + def maxSubArrayFromIndex(begin: int, end: int) -> int: + if begin == end: + return nums[begin] + middle = (begin + end) // 2 + return max( + maxSubArrayFromIndex(begin, middle), + maxSubArrayFromIndex(middle+1, end), + prefix_sums[middle] + suffix_sums[middle+1]) + + return maxSubArrayFromIndex(0, len(nums)-1) + ``` + + - prefix_sumsやsuffix_sumsを予め作っておくことで辛うじてO(n)になっているが、作らなければO(n log n)になるとのこと + - 分割統治するlog n回ごとにprefix/suffixの計算が必要 + - prefix_sumだけで書こうとすると難しそうだが一応できるらしい + - https://github.com/hayashi-ay/leetcode/pull/36/commits/5be8e6aaeb3c791a741578818022a836110239c5#diff-a6956948eb5bc3137495f6d70424f00900c8ba03395ebacccf937a76b9a4d988R53 + - 流れは追いやすかった +- 文字数が長かったり、インデックスを1から始めたりするのは読みづらい + - https://github.com/hayashi-ay/leetcode/pull/36/files#diff-a6956948eb5bc3137495f6d70424f00900c8ba03395ebacccf937a76b9a4d988R85 +- 考え方として標高という捉え方が出来るらしい + - https://github.com/olsen-blue/Arai60/pull/32/files#diff-a6956948eb5bc3137495f6d70424f00900c8ba03395ebacccf937a76b9a4d988R8 + - 感覚の問題だが、個人的には積み木を引き継ぐイメージ + - マイナスだったら当然引き継げない + - ただ、こういう理解だったからこそマイナスが解になる場合を逃してしまったのでイメージに頼りつつも実際のエッジケースは幅広く具体的に見たいところ +- prefix_sumについての意見があった + - https://github.com/fhiyo/leetcode/pull/33/files#r1667620608 + - 自分の認識では、prefix_sumsが配列でprefix_sumはその時点までの累積和という意味なので問題ないはず + +## Step 3. Final Solution + +- max()を使わずにif文を使う方が関数呼び出しがない分速そう + +```python +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + max_sum = nums[0] + prefix_sum = 0 + for num in nums: + prefix_sum += num + if max_sum < prefix_sum: + max_sum = prefix_sum + if prefix_sum < 0: + prefix_sum = 0 + return max_sum +```