-
Notifications
You must be signed in to change notification settings - Fork 0
3. Longest Substring Without Repeating Characters #52
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,19 @@ | ||
| class Solution { | ||
| public: | ||
| int lengthOfLongestSubstring(string s) { | ||
| int longest_length = 0; | ||
|
|
||
| for (int start = 0; start < s.size(); start++) { | ||
| set<char> unique_letters; | ||
| for (int end = start; end < s.size(); end++) { | ||
| if (unique_letters.contains(s[end])) { | ||
| break; | ||
| } | ||
| unique_letters.insert(s[end]); | ||
| longest_length = max(longest_length, end - start + 1); | ||
| } | ||
| } | ||
|
|
||
| return longest_length; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| ## ステップ1 | ||
| まず思いついた方法は総当たりで解く方法。 | ||
| substringを作るための開始点と終了点の2つのインデックス用意する。 | ||
| setに一文字ずつ記録し重複があるのかないのか管理。 | ||
| TLEにはならないが、2つのループで全ての位置を試しているため時間計算量がO(n^2)、空間計算量はO(n) | ||
|
|
||
| 次にsliding windowで考える。 | ||
| こちらもsubstringを作るための開始点と終了点の2つのインデックス用意する。 | ||
| 全ての位置を試すのではなく、必要な場合のみインデックスを動かす。 | ||
|
|
||
| 重複がない間は、set内に文字を入れながら終了点を後ろにずらす。 | ||
| 重複があれば開始点の位置を前に進める。またsetから開始点にあった文字を削除する。 | ||
|
|
||
| ## ステップ2 | ||
| ・setの変数名をunique_lettersにしたが、setに対してuniqueは助長か。 | ||
| setの中身は重複しないため。 | ||
|
|
||
| ・setからmapへの管理方法に変更 | ||
| mapを用いて文字ごとの登場回数を記録する方法ではsetと同じような処理になる。 | ||
| この場合setの方がシンプルな構造なのでsetが好み。 | ||
|
|
||
| mapには文字ごとのindexを記録する。 | ||
| これによりwhileループで開始位置を動かしていた処理をなくすことができる。 | ||
|
|
||
| ・変数名はstartとendよりleftとrightが一般的か | ||
|
|
||
| ## ステップ3 | ||
| **3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** | ||
|
|
||
| ## 他の方の解法 | ||
| 基本方針は同じ | ||
| https://github.com/katsukii/leetcode/pull/5/commits/7dee757451b863e0166c44d43329c6863b6ac6d9 | ||
| https://github.com/Yoshiki-Iwasa/Arai60/pull/42 | ||
|
|
||
| 文字コードを使って使って、インデックスを管理する方法 | ||
| レビューやり取りを見ていると理解できていない箇所がちらほらあるので別途調べる | ||
| https://github.com/philip82148/leetcode-arai60/pull/3 | ||
|
|
||
| 自分もsetを使う方が好みでした。 | ||
| みなさん指摘されている通りindexも管理して、それを使って範囲を狭める方が効率的ですよね。 | ||
| https://github.com/fhiyo/leetcode/pull/48/commits/77b26c5a02d26112cd7ff94bf4d330afdde8a68a | ||
|
|
||
| ## Discorなど | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| class Solution { | ||
| public: | ||
| int lengthOfLongestSubstring(string s) { | ||
| int longest_length = 0; | ||
|
|
||
| set<char> unique_letters; | ||
| int start = 0; | ||
| for (int end = 0; end < s.size(); end++) { | ||
| while (unique_letters.contains(s[end])) { | ||
| unique_letters.erase(s[start]); | ||
| start++; | ||
| } | ||
|
|
||
| unique_letters.insert(s[end]); | ||
| longest_length = max(longest_length, end - start + 1); | ||
| } | ||
|
|
||
| return longest_length; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| class Solution { | ||
| public: | ||
| int lengthOfLongestSubstring(string s) { | ||
| int longest_length = 0; | ||
|
|
||
| map<char, int> letters_to_index; | ||
| int left = 0; | ||
| for (int right = 0; right < s.size(); right++) { | ||
| if (letters_to_index[s[right]] > 0) { | ||
| // left = letters_to_index[s[right]]だと現地点より前に | ||
| // 重複があった場合そこの位置をleftにしてしまう | ||
| left = max(letters_to_index[s[right]], left); | ||
| } | ||
| longest_length = max(longest_length, right - left + 1); | ||
| // 重複が発生した際に、その次の位置をleftにするためここで+1して記録 | ||
| letters_to_index[s[right]] = right + 1; | ||
| } | ||
|
|
||
| return longest_length; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| class Solution { | ||
| public: | ||
| int lengthOfLongestSubstring(string s) { | ||
| int longest_length = 0; | ||
|
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. どちらでもいいんですがmax_len(gth)という選択肢もあります(短いので)
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. @philip82148 レビューありがとうございます。そうですね。少しlongest_lengthは長いと感じてました。。。 |
||
| map<char, int> letters_to_index; | ||
|
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. mapなら単数to単数/複数がいいと思います!letter_to_index等 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. また、今回の場合ascii128文字なので、配列にするのもありです。
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 left = 0; | ||
| for (int right = 0; right < s.size(); right++) { | ||
|
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. 僕はleftやright、begin/endが半開区間([begin, end))のイメージがあり、(もしかしたらそれを気にしないで書くことも多いのかもしれませんが)、ちょっと余計なことを考えてしまいそうなので、僕の回答では[begin, i]で書いていましたね。(どちらでもいいと思います)
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.
これはbinary searchの問題を解く中でleft right が必ずしも半開区間という考え方は無くなりました。
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. ご参考までに共有ですが、リーダブルコードには、begin/endが [begin, end)半開区間、start/lastが [start, last]閉区間のイメージということが記載されていました。 |
||
| if (letters_to_index[s[right]] > 0) { | ||
| left = max(letters_to_index[s[right]], left); | ||
| } | ||
| longest_length = max(longest_length, right - left + 1); | ||
| letters_to_index[s[right]] = right + 1; | ||
| } | ||
|
|
||
| return longest_length; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| class Solution { | ||
| public: | ||
| int lengthOfLongestSubstring(string s) { | ||
| int longest_length = 0; | ||
| // ASCII文字用の配列を-1で初期化 | ||
| vector<int> letters_to_index(128, -1); | ||
| int left = 0; | ||
|
|
||
| for (int right = 0; right < s.size(); right++) { | ||
| if (letters_to_index[s[right]] != -1) { | ||
| left = max(letters_to_index[s[right]] + 1, left); | ||
| } | ||
| longest_length = max(longest_length, right - left + 1); | ||
| letters_to_index[s[right]] = right; | ||
| } | ||
|
|
||
| return longest_length; | ||
| } | ||
| }; |
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.
特に問題ないです。計算量は文字の種類が m とすると、O(mn) でも抑えられてしまいそうですね。
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.
@oda
レビューありがとうございます。総当たりだからすぐ「だめ」とみなす姿勢は改めないとですね。