こんにちは
今回の学びは
・「次のこの問題を解くばあい知っていればよい一つの事実とは?」でフックを増やせ
・解きまくって量を増やしてひらめきを早くしよう!
・で、連続するなになにとくれば、それまでの合計を持ち歩くことができそうです
・kadane方式です。index J で終わるサブ配列を考えるのが味噌
問題はeasyですが、mediumくらいは有る感じです。
(時間配分は5分問題理解 10分検討 10分実装 20分振り返り の一文45分構成)
まずは入出力をしっかりおさえましょう。
なんどもサンプルを汚して
ようやく思いつく問題にはどうしたら
もっと早くおもいつくのか?
もっと早くとけるのか?
これには焦らず、量とフックを増やしましょう。(ひらめく方法のググり結果を参照)
量はleetcodeやatcoderなどの問題を数多く解くこと
フックは、毎回その問題から「次のこの問題を解くばあい知っていればよい一つの事実とは?」と (※1)
自問してその答えを用意しておこう
持ちろん、本記事のように学びを抽出していくことも効果はあるとおもう。
実装前後でこれは毎回書きましょう。timespace analysis (時間とスペースの分析)は
実際の実装はこちら
import sys sys.setrecursionlimit(314159265) class Solution: def maxSubArray(self, nums: List[int]) -> int: pre = -sys.maxsize i = 0 # left pointer total = 0 maxi = -sys.maxsize for j in range(len(nums)): curr = nums[j] #print("i:%s, j:%s, curr:%s, total:%s" % (i, j, curr, total)) if total + curr > curr: #print("継続") total += curr maxi = max(maxi, total) elif total + curr < curr: #print("一回リセットししょ") maxi = max(maxi, total) total = curr maxi = max(maxi, total) i = j else: #print("まぁ継続") total += curr maxi = max(maxi, total) pre = curr # 最後にもう一回しておく必要がある maxi = max(maxi, total) return maxi
実装後です。timespace analysis (時間とスペースの分析)は ◯◯
「次のこの問題を解くばあい知っていればよい一つの事実とは?」
これまで、と現在を比較、悪い過去は切り捨て戦法、となづけました
最後に考えがごちゃついている実装なので掃除したバージョンをアップします
こちら
class Solution: def maxSubArray(self, nums: List[int]) -> int: total = 0 maxi = -2147483647 for j in range(len(nums)): curr = nums[j] past = total + curr if past > curr: total += curr elif past < curr: total = curr else: total += curr maxi = max(maxi, total) return maxi
変数大事〜
pastにしただけでだいぶ読みやすくなったし
あとこの問題
contiguous(隣接する)とあります
連続すると、捉えてもいいです。
で、連続するなになにとくれば、それまでの合計を持ち歩くことができそうです
と、ここまでが最初の記事だったのですが、この最初の記事から4ヶ月ぶりにこの問題に
再び向かったのですが、残念ながら全く解けませんでしたw。
解法はいくつかあります。leetcodeのソリューションはこちらです。
分割統治法(devide and concur)と
greedyと
Dynamic Programming で、このmaxium subarrayにおいては kadane's algorithm という名前がついているものです。
kadane's algorithm は説明動画はこちらがわかりやすかったです。Dynamic Programmingで縦軸に同じく配列を撮って
starting indexとしてi-thからサブ配列を始めた時のmaxSubarrayと自然にしたいところですが、これだとO(N^2)でBFと変わりません。そこで、
要素が連続という点と、うまく以前の結果を再利用という、ヒントから
f(i) = f(i - 1) + nums[i] 的な式を立てたのが、kadane方式です。index J で終わるサブ配列を考えるのが味噌で、
これによってO(N)で処理が終わります
kadaneの実装はこちら
class Solution: def maxSubArray(self, nums: List[int]) -> int: N = len(nums) if N == 0: return 0 dp = [0] * N dp[0] = nums[0] maxi = nums[0] for i in range(1, N): dp[i] = max( dp[i-1] + nums[i], nums[i] ) maxi = max(maxi, dp[i]) return maxi
devide and concurはこちらの説明動画をみて理解しました。
まとめ
・「次のこの問題を解くばあい知っていればよい一つの事実とは?」でフックを増やせ
・解きまくって量を増やしてひらめきを早くしよう!
・で、連続するなになにとくれば、それまでの合計を持ち歩くことができそうです
・kadane方式です。index J で終わるサブ配列を考えるのが味噌
以上です