-
Notifications
You must be signed in to change notification settings - Fork 0
53. Maximum Subarray #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| # Step1 | ||
|
|
||
| かかった時間:12min | ||
|
|
||
| 計算量:nums.length = Nとして | ||
|
|
||
| 時間計算量:O(N) | ||
|
|
||
| 空間計算量:O(N) | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| maximum_subarray_so_far = [0] * len(nums) | ||
| maximum_subarray_so_far[0] = nums[0] | ||
| for i in range(1, len(nums)): | ||
| maximum_subarray_so_far[i] = max( | ||
| maximum_subarray_so_far[i - 1] + nums[i], | ||
| nums[i] | ||
| ) | ||
|
|
||
| return max(maximum_subarray_so_far) | ||
| ``` | ||
|
|
||
| 思考ログ: | ||
| - 1個前までのmaximum_subarrayから更に伸ばした方がいいか、一旦切るか考える | ||
| - 最初```maximum_subarray_so_far[-1]```を反射的に返してしまった | ||
| - 配列の要素の意味をちゃんと確認すること | ||
|
|
||
| # Step2 | ||
|
|
||
| 講師役目線でのセルフツッコミポイント: | ||
|
|
||
| 参考にした過去ログなど: | ||
| - https://github.com/seal-azarashi/leetcode/pull/30 | ||
| - https://github.com/Ryotaro25/leetcode_first60/pull/35 | ||
| - https://github.com/Yoshiki-Iwasa/Arai60/pull/48 | ||
| - https://github.com/fhiyo/leetcode/pull/33 | ||
| - 再帰の実装 | ||
| - https://github.com/goto-untrapped/Arai60/pull/30 | ||
| - https://github.com/YukiMichishita/LeetCode/pull/13 | ||
| - 色々な解放がコンパクトにまとめてあるので復習時に参照したい | ||
| - https://github.com/sakupan102/arai60-practice/pull/33 | ||
| - ```prefix_sum - min_prefix_sum```から```current_sum```を作る(Kadane) | ||
| - https://github.com/sakupan102/arai60-practice/pull/33/files#r1611415355 | ||
| - https://github.com/SuperHotDogCat/coding-interview/pull/14 | ||
| - 分割統治 | ||
| - https://github.com/shining-ai/leetcode/pull/33 | ||
| - 分割統治 | ||
| - https://github.com/hayashi-ay/leetcode/pull/36 | ||
| - 分割統治 | ||
|
|
||
| step1を配列を使わずに | ||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| maximum_subarray_sum = -sys.maxsize | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
あとは
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
あたりの選択肢で揺れてますが、今回はこれにしました(intにしておきたい、くらいで深い意味はないです) |
||
| prefix_sum = 0 | ||
| for num in nums: | ||
| prefix_sum = max(prefix_sum + num, num) | ||
| maximum_subarray_sum = max(maximum_subarray_sum, prefix_sum) | ||
|
|
||
| return maximum_subarray_sum | ||
| ``` | ||
| 思考ログ: | ||
| - 配列が必要かどうか、は考えておきたい(DPだと反射的に配列を用意しがち) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DPだと反射的に配列を用意しがち という自省メモのつもりでした。 ご指摘のとおり、DPの性質上、配列をよく使うという話なのですが、DPだ->配列用意しよう、のような脳死ムーブを(私が)しがちな気がしたので。 |
||
|
|
||
| 再帰 | ||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらの解法よりstep1のボトムアップやや累積和がいいと思いました。 一方でこの問題は他に比べて再帰で解くのは難しいと思いました。。。 |
||
| def max_sub_array_helper(i: int) -> tuple[int]: | ||
| if i == 0: | ||
| return nums[0], nums[0] | ||
|
|
||
| prefix_sum, max_sub_array_sum = max_sub_array_helper(i - 1) | ||
| prefix_sum = max(nums[i], prefix_sum + nums[i]) | ||
| max_sub_array_sum = max(max_sub_array_sum, prefix_sum) | ||
| return prefix_sum, max_sub_array_sum | ||
|
|
||
| prefix_sum, max_sub_array_sum = max_sub_array_helper(len(nums) - 1) | ||
| return max_sub_array_sum | ||
| ``` | ||
| 思考ログ: | ||
| - 以下で実装されていたのでやってみる | ||
| - https://github.com/fhiyo/leetcode/pull/33/files | ||
| - nonlocalをやめて返り値で渡していく方式にしてみた | ||
| - あとで見て気づいたが、ここだけ```sub_array```にしてるの気になる(元の関数はSubArrayだからsub_arrayにしたのだろう) | ||
|
|
||
| 累積和を求めて全探索(TLE) | ||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| prefix_sum = [0] | ||
| for num in nums: | ||
| prefix_sum.append(prefix_sum[-1] + num) | ||
|
|
||
| maximum_subarray_sum = nums[0] | ||
| for i in range(len(prefix_sum) - 1): | ||
| for j in range(i + 1, len(prefix_sum)): | ||
| maximum_subarray_sum = max( | ||
| maximum_subarray_sum, | ||
| prefix_sum[j] - prefix_sum[i] | ||
| ) | ||
|
|
||
| return maximum_subarray_sum | ||
| ``` | ||
| 思考ログ: | ||
| - 計算量的に通らないなと思って実装しなかったもの | ||
| - https://discord.com/channels/1084280443945353267/1206101582861697046/1208473290881110117 | ||
| > どうせ、1番上は思いついたけれども、価値のないものだと思って捨てたでしょう。 | ||
|
|
||
| 今まで見た中で最小のprefix_sumを記録しておく方法 | ||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| min_prefix_sum_so_far = 0 | ||
| prefix_sum = 0 | ||
| maximum_subarray_sum = nums[0] | ||
| for num in nums: | ||
| prefix_sum += num | ||
| maximum_subarray_sum = max( | ||
| maximum_subarray_sum, | ||
| prefix_sum - min_prefix_sum_so_far | ||
| ) | ||
| min_prefix_sum_so_far = min(min_prefix_sum_so_far, prefix_sum) | ||
|
|
||
| return maximum_subarray_sum | ||
| ``` | ||
| 思考ログ: | ||
| - 累積和の履歴で最も小さかったもの(谷底)から現在までの距離を測ることで要素和が最大の部分列を探していく | ||
|
|
||
| # Step3 | ||
|
|
||
| かかった時間:2min | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| maximum_subarray_sum = nums[0] | ||
| prefix_sum = 0 | ||
| for num in nums: | ||
| prefix_sum = max(prefix_sum, 0) + num | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. このアルゴリズムも prefix_sum が「num を配列の最後の値として使うことに決めた場合の、連続する配列の和の最大値」という意味だと思うと理解できますね。 |
||
| maximum_subarray_sum = max(maximum_subarray_sum, prefix_sum) | ||
|
|
||
| return maximum_subarray_sum | ||
| ``` | ||
| 思考ログ: | ||
| - ```prefix_sum```の更新で```num```を外に出してみた | ||
|
|
||
| # Step4 | ||
|
|
||
| ```python | ||
| ``` | ||
| 思考ログ: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
一応、ここの意味を自然言語で説明してくれませんか。
「maximum_subarray_so_far[i] の意味は nums[i] が和として使用する最後の数であった場合、連続する配列の和の最大値」ですね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。
変数名の情報だけでは不十分でした。コメントを残すように心がけます。
nums[i]が最後の要素になるような部分列集合を全て考え、各部分列の和をそれぞれ取って、そのうち最大のものを要素とする配列、みたいな感じですかね。日本語が難しい、、
maximum_subarray_so_far[i] = max {Σ_k (A_ij[k])} (∀ j)
A:対象とする部分列の配列
i : nums[i]と対応、対象とする部分列集合の最後の要素 = nums[i]
j : 対象とする部分列集合のインデックス
k : 対象とする部分列の要素のインデックス
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あー、いや、コメントが必要だというよりは、言語化しておいたほうが理解が深まるだろうと思ったので書いておいたくらいです。