こんにちは
今回の学びは
・ソートされた配列と二分木はよく似てるよ。
・できれば二分木探索を配列で実装していて 🙂
問題はlongest-substring-without-repeating-characters
(時間配分は5分問題理解 10分検討 10分実装 20分振り返り の一文45分構成)
まずは入出力をしっかりおさえましょう。
この問題は後に勉強してわかったことなのですが
sliding windowのテンプレートがうまく使えます。
もうすこしちゃんというとhmapを利用した条件判定とsliding windowの組み合わせた技です。
まずは、
この知識がなかった時にどのように解いたか見てみましょう。
sofarとうマップにindexを保持させて、条件が外れた時に(条件が外れた時とは、この場合、重複が起きてしまっと時)
そこまで戻って操作を繰り返すやりかたで、中々秀逸である。
悪くない。ただこの回答にこぎつくまでの時間はながかったと記憶している。
class Solution: def lengthOfLongestSubstring(self, s): """ :type s: str :rtype: int """ import sys from collections import defaultdict sofar = {} i = 0 maxi = tmp = 0 while True: if i == len(s): break cur = s[i] if cur not in sofar.keys(): # まだ sofar[cur] = i tmp +=1 maxi = max(tmp, maxi) i+=1 else: # あかん、リセット next_i = sofar[cur] + 1 tmp = 0 sofar = {} i = next_i return maxi
途中、こういう解き方もしている。
しかし、再現性がすくない。というのも数週間後、読み返すと読みづらい。。何を書いているの
難しい。メンテしずらい。。。
そのコードはこれ。アイデアはいいが変数名とか、ちょっとロジックごっちゃっていて読みにくいと感じた。
from collections import defaultdict class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # remember last index # if same char, curr - last index. # update the maxi all the time # O(n) algorithm memo = defaultdict(lambda : -1) maxi = 0 j = -1 for i, c in enumerate(s): if memo[c] >= 0: # already exist if j > memo[c]: cur = i - j + 1 else: cur = i - memo[c] maxi = max(maxi, cur) j = max(j, memo[c] + 1) else: extra = 1 if j >= 0 and s[j] != s[i] else 0 maxi = max(maxi, i-j+extra) memo[c] = i return maxi
その後も何度かこの問題とは対峙してきたようだ。
久しぶりに解いて
一瞬で解けたから、成長したかなーと実感した。
class Solution: def lengthOfLongestSubstring(self, S: str) -> int: if S is None or len(S) == 0: return 0 sz = len(S) l = 0 r = 1 maxi = 1 while l < sz and r < sz: print("l -> %s, r -> %s" % (l, r)) if S[r] in S[l:r]: # move l until non overlap point while S[l] != S[r]: l += 1 l += 1 else: maxi = max(maxi, r - l + 1) # move r +1 r += 1 return maxi
tO(N^2)がかかっていると思います。この s[r] in S[l:r]はコスティだと思う。
まぁ、実際はスコアとスピードは早かった。
しかし、次の問題(substring with concatination of all words)で玉砕されたのだけどw
という
ながれでsliding templateを勉強したんですが、
実際、それを
利用して、テンプレートを利用しても解いています。
from collections import defaultdict class Solution: def lengthOfLongestSubstring(self, S: str) -> int: maxi: int = 0 hmap: DefaultDict[str, int] = defaultdict(int) counter = len(hmap) l = r = 0 # sliding window pointers while r < len(S): #print("l:%s, r:%s, counter:%s, hmap:%s" % (l, r, counter, hmap)) c = S[r] hmap[c] += 1 if hmap[c] > 1: counter += 1 # 違反 r += 1 # l(left) pointerと管理変数をクリアするロジック while counter > 0: # depends on condition #--- business logic --- cl = S[l] # c(character) at left pointer hmap[cl] -= 1 if cl == c and hmap[cl] < 2: counter -= 1 # break l += 1 # save or update the result if find T maxi = max(maxi, r - l) return maxi
実装後です。timespace analysis (時間とスペースの分析)は ◯◯
「次のこの問題を解くばあい知っていればよい一つの事実とは?」
スライディングtemplateをつかえるよ。
まとめ
以上です