-
Notifications
You must be signed in to change notification settings - Fork 0
Create 0003-longest-substring-without-repeating-characters.md #49
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
Open
docto-rin
wants to merge
1
commit into
main
Choose a base branch
from
0003-longest-substring-without-repeating-characters.md
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+88
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
...out-repeating-characters/0003-longest-substring-without-repeating-characters.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| ## Step 1 | ||
|
|
||
| - 問題文 | ||
| - 文字列`s`が与えられる。重複した文字を使わない最長の部分文字列(substring)の長さを返せ。 | ||
| - 制約: | ||
| - 0 <= s.length <= 5 * 10^4 | ||
| - s consists of English letters, digits, symbols and spaces. | ||
|
|
||
| ### 実装1 | ||
|
|
||
| - アルゴリズムの選択 | ||
| - 部分文字列は連続している必要があるので、greedyに解決する可能性がある。 | ||
| - 左から走査し、これまでの文字と重複がないかを見るにはstr.findを使えば良いだろう。 | ||
| - 重複があった(登場が2回目の文字だった)場合、1回目の文字とそれより左は今後関心がなくなる。 | ||
| - 逆に1回目の登場位置より右はまだsubstringの長さが伸びる可能性を秘めている。 | ||
| - 自然とダブルポインタ(sliding window)に行き着く。 | ||
| - 実装 | ||
| - loopで手軽に実装 | ||
| - 計算量 | ||
| - Time: O(n^2) | ||
| - 実際にはstr.findの恩恵で速いはず。 | ||
| - Space: O(1) | ||
|
|
||
| ```python3 | ||
| class Solution: | ||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||
| first = 0 | ||
| max_length = 0 | ||
| for last in range(1, len(s)): | ||
| found = s.find(s[last], first, last) | ||
| if found == -1: | ||
| continue | ||
| # substring is from first to last - 1 | ||
| max_length = max(max_length, last - first) | ||
| first = found + 1 | ||
| return max(max_length, len(s) - first) | ||
| ``` | ||
|
|
||
| - ここまで5分 | ||
| - 最初、return max(max_length, len(s) - first)のlen(s)をlastと書いてしまい、s=""のエッジケースでUnboundLocalErrorになってしまった。 | ||
| - 解決策として、returnの部分をlen(s)にする他、最初にlast = 0と初期化しておくなど。 | ||
| - または、max_lengthを常に更新するようにする。 | ||
| - 1回目にはやく書けたのが嬉しくて慌ててsubmitしたことを非常に後悔しました。 | ||
|
|
||
| ## Step 2 | ||
|
|
||
| - [コメント集](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0) | ||
| - https://discord.com/channels/1084280443945353267/1322513618217996338/1352231179083841536 | ||
| - > -1 がでてくればいいので、seen_char_to_index.get(s[right], -1)と使えば、条件分岐を回避できますね。 | ||
| - dict.getはキーがないとNone、もしくは引数で渡したデフォルト値にフォールバックする。 | ||
| - 強化学習により極度にエラーを恐れているCoding Agentがエラーを握り潰すためによく書いてくるやつ... | ||
| - https://github.com/olsen-blue/Arai60/pull/49 | ||
| - setや辞書などのhashtableを使う方法は最初に思いついたが、in判定するなら入力`s`のスライスをそのまま活用すればいいと思い、findに移行した。 | ||
| - 前者は一応時間計算量はO(n)だが、ハッシュの計算が定数倍でのしかかるのと、str.find()がネイティブコードで高速なので、いい勝負しそう。 | ||
| <details> | ||
| <summary>find vs dict ベンチマーク by GPT-5</summary> | ||
|
|
||
| <img width="990" src="https://github.com/user-attachments/assets/0df0dbf4-8940-4ff5-bb04-b9744e58bbc2" /> | ||
| <img width="990" src="https://github.com/user-attachments/assets/36ecf4eb-7681-45f0-b478-97de3a133e6c" /> | ||
| </details> | ||
| - all-uniqueだと倍くらいにはなっているが、findもだいぶ善戦している。 | ||
| - まぁけれども、汎用的にはdictのが良さそうか。 | ||
|
|
||
| ### 実装2 | ||
|
|
||
| - 辞書で各文字が最後に現れたインデックスを管理。 | ||
| - 計算量 | ||
| - Time: O(n) | ||
| - Space: O(n) | ||
|
|
||
| ```python3 | ||
| class Solution: | ||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||
| last_seen = {} | ||
| left = 0 | ||
| max_length = 0 | ||
|
|
||
| for right, character in enumerate(s): | ||
| left = max(left, last_seen.get(character, -1) + 1) | ||
| last_seen[character] = right | ||
| max_length = max(max_length, right - left + 1) | ||
|
|
||
| return max_length | ||
| ``` | ||
|
|
||
| ## Step 3 | ||
|
|
||
| [実装2](#実装2) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
left = -1 で考えるのも一つかもしれません。