-
Notifications
You must be signed in to change notification settings - Fork 0
Solved Arai60/3. Longest Substring Without Repeating Characters #47
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,113 @@ | ||||||||||||||
| ## Step 1. Initial Solution | ||||||||||||||
|
|
||||||||||||||
| - 文字列が与えられて重複しない部分文字列の最長長を調べる | ||||||||||||||
| - 文字列は英字, 数字, 記号, スペースもあり | ||||||||||||||
| - 前から見て行って重複しない間は長さを見る | ||||||||||||||
| - 重複したら重複以降を保持して続ける | ||||||||||||||
| - そんなに苦戦せずに書けた | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| class Solution: | ||||||||||||||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||||||||||||||
| max_length = 0 | ||||||||||||||
| substring = "" | ||||||||||||||
| for char in s: | ||||||||||||||
| duplicate_place = substring.find(char) | ||||||||||||||
| if duplicate_place == -1: | ||||||||||||||
| substring += char | ||||||||||||||
|
|
||||||||||||||
| substring_length = len(substring) | ||||||||||||||
| if substring_length > max_length: | ||||||||||||||
| max_length = substring_length | ||||||||||||||
| else: | ||||||||||||||
| substring = substring[duplicate_place + 1:] + char | ||||||||||||||
| return max_length | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| ### Complexity Analysis | ||||||||||||||
|
|
||||||||||||||
| - 時間計算量:O(N^2) | ||||||||||||||
| - 空間計算量:O(N) | ||||||||||||||
|
|
||||||||||||||
| ## Step 2. Alternatives | ||||||||||||||
|
|
||||||||||||||
| - もう少し効率の良いやり方はありそう | ||||||||||||||
| - 各charの位置を辞書で保存すれば探す処理はO(1)で済むが更新に時間がかかる | ||||||||||||||
| - https://github.com/tokuhirat/LeetCode/pull/48/files#diff-59fd806da6e42daeb12a7afabcd326ca6953f65144e488ba169167138a8c2598R2-R4 | ||||||||||||||
| - 開始位置ごとに最後までiteration | ||||||||||||||
| - 中身は少し違うが計算量は同じ | ||||||||||||||
| - end_indexが動くのは少し分かりにくかった | ||||||||||||||
| - https://github.com/hayashi-ay/leetcode/pull/47/files#diff-eaf04e4839867b1c256a01b37e3fd908cd889582123148e5910d72e4e4fcb421R26 | ||||||||||||||
| - 確かに更新する必要はないか。現在地との差分を考えるこれでO(N)で計算できる | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| class Solution: | ||||||||||||||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||||||||||||||
| substring_start_position = -2 | ||||||||||||||
| max_length = 0 | ||||||||||||||
| char_to_position = defaultdict(lambda: -1) | ||||||||||||||
| for index, char in enumerate(s): | ||||||||||||||
|
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. position と index が同じ意味で使われている点に違和感を感じました。どちらかに統一するとよいと思います。
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. どちらが良いか迷って混在させてしまってました。修正するようにします |
||||||||||||||
| duplicate_position = char_to_position[char] | ||||||||||||||
|
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. duplicate_position ですと、 duplicate が動詞のため、関数名のように感じられました。また、直訳すると「重複した位置」となり、表現したいこことずれているように感じされました。自分なら、 last_position と名付けると思います。 |
||||||||||||||
| char_to_position[char] = index | ||||||||||||||
| if duplicate_position >= substring_start_position: | ||||||||||||||
| substring_start_position = duplicate_position + 1 | ||||||||||||||
| max_length = max(max_length, \ | ||||||||||||||
| index - substring_start_position + 1) | ||||||||||||||
|
Comment on lines
+54
to
+55
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.
Suggested change
こちらのスタイルの方がよく見る気がします。 |
||||||||||||||
| return max_length | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| - https://github.com/olsen-blue/Arai60/pull/49/files#r2005295464 | ||||||||||||||
| - defaultdictを使わずにdict.get(x ,-1)としても良い | ||||||||||||||
| - この方が読んでいる側からすると脳内メモリを解放されて楽に読める | ||||||||||||||
| - setでも試す | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| class Solution: | ||||||||||||||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||||||||||||||
| chars_in_window = set() | ||||||||||||||
| left_index = 0 | ||||||||||||||
| max_length = 0 | ||||||||||||||
| for right_index, char in enumerate(s): | ||||||||||||||
| while char in chars_in_window: | ||||||||||||||
| chars_in_window.remove(s[left_index]) | ||||||||||||||
| left_index += 1 | ||||||||||||||
| chars_in_window.add(char) | ||||||||||||||
| length = right_index - left_index + 1 | ||||||||||||||
| max_length = max(max_length, length) | ||||||||||||||
| return max_length | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| ## Step 3. Final Solution | ||||||||||||||
|
|
||||||||||||||
| - setで書く方法が同時に覚えておく必要のある事が少ないので嬉しい | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| class Solution: | ||||||||||||||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||||||||||||||
| max_length = 0 | ||||||||||||||
| substr_start = 0 | ||||||||||||||
| chars_in_substr = set() | ||||||||||||||
| for substr_end, char in enumerate(s): | ||||||||||||||
|
Comment on lines
+89
to
+91
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. start, endはsliding windowを閉区間で表した時の両端点として使われていますが、Python documentationなどでは一貫して半開区間[start, end)の両端点として使われています。 例:https://docs.python.org/3/library/stdtypes.html#str.find
ちなみに、start, stopも同様です。
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. 確かにその観点は抜けていたので参考にします |
||||||||||||||
| while char in chars_in_substr: | ||||||||||||||
| chars_in_substr.remove(s[substr_start]) | ||||||||||||||
| substr_start += 1 | ||||||||||||||
| chars_in_substr.add(char) | ||||||||||||||
| max_length = max(max_length, substr_end - substr_start + 1) | ||||||||||||||
| return max_length | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| - string.findを使う方法も悪くはない | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| class Solution: | ||||||||||||||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||||||||||||||
| max_length = 0 | ||||||||||||||
| substring_start = 0 | ||||||||||||||
| for substring_end, char in enumerate(s): | ||||||||||||||
| duplicate_position = s.find(char, substring_start, substring_end) | ||||||||||||||
| if duplicate_position != -1: | ||||||||||||||
| substring_start = duplicate_position + 1 | ||||||||||||||
| max_length = max(max_length, substring_end - substring_start + 1) | ||||||||||||||
| return max_length | ||||||||||||||
|
Comment on lines
+103
to
+112
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. substring_startの左隣を変数に置くと更新式で+1の修正が不要になり、またsubstringの距離も半開区間の両端点の差になってわかりやすくなるかもです。 class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
max_length = 0
passed_tail = -1
for substring_tail, ch in enumerate(s):
last_found = s.find(ch, passed_tail + 1, substring_tail)
if last_found != -1:
passed_tail = last_found
max_length = max(max_length, substring_tail - passed_tail)
return max_lengthThere 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. 上の if last_found != -1:
passed_tail = last_foundのところは、 passed_tail = max(passed_tail, last_found)とも書けますね。これは趣味の範囲だと思います。 |
||||||||||||||
| ``` | ||||||||||||||
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.
charはC、C++、Javaなどの予約語(基本データ型)charと被るので他言語に慣れた読み手に配慮して自分は避けるようにしています。
cかchがよくみます。ちなみにchrはPythonの組み込み関数にあるので避けます。