Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions medium/3/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Step1

かかった時間:15min

計算量:

文字列の長さをNとして
- 時間計算量:O(N)
- 空間計算量:O(N)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

かなり前のPRへのコメントで恐縮ですが、この問題の制約に

s consists of English letters, digits, symbols and spaces.

とあるので、入力の文字列がめちゃめちゃ大きくなったとしても、substringはあるサイズで頭打ちになる -> 空間計算量はO(1)な気がします。


```python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
start = 0
stop = 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stop より last の方が実態を表していてより適切と書籍(リーダブルコード)で読んだことがあります。

substring_chars = set()
longest_substring_len = 0
while stop <= len(s):
c = s[stop - 1]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好みの範疇かもしれませんが、stop (last) のほうが、それを含まないインデックスであるというのは少し違和感があります。
二分探索だと右端を含むか含まないかというのはむしろ自由に書き換えられたほうがよいとは思うのですが、ここは文字列のそのインデックスにアクセスしているので、s[stop] になるように書くのが自然な印象です (そうすると長さを求める部分は stop - start + 1 になりますね)。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私もこっちのほうが好みです。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういうコメントを頂いた背景があります。
#38 (comment)

while c in substring_chars:
substring_chars.remove(s[start])
start += 1

substring_chars.add(c)
longest_substring_len = max(
longest_substring_len,
stop - start
)
stop += 1

return longest_substring_len
```
思考ログ:
- 文字列を延ばしていって、現在の部分文字列に重複が出たら、重複が解消されるまで頭を進める、を文字列の終わりまで繰り返す

# Step2

講師役目線でのセルフツッコミポイント:
- ```while stop < len(s): stop += 1```は、for文に直そうという気持ちになってほしい

参考にした過去ログなど:
- https://github.com/ryosuketc/leetcode_arai60/pull/37
- https://github.com/Kaichi-Irie/leetcode-python/pull/9
- 出現した最後のインデックスを覚えておく
- https://github.com/yakataN/Arai60/pull/3
- https://github.com/skypenguins/coding-practice/pull/3
- https://github.com/fuga-98/arai60/pull/47
- https://github.com/hroc135/leetcode/pull/45
- https://github.com/olsen-blue/Arai60/pull/49
- https://github.com/olsen-blue/Arai60/pull/49#discussion_r2005295464
- https://github.com/Ryotaro25/leetcode_first60/pull/52
- 文字種類の制限から全探索の計算量はもう少し絞れる
- https://github.com/Ryotaro25/leetcode_first60/pull/52#discussion_r1981068549
- https://github.com/katsukii/leetcode/pull/5
- 出現回数を記録していってもいい
- https://github.com/katsukii/leetcode/pull/5/files#r1896477073
- https://github.com/philip82148/leetcode-swejp/pull/3
- スタック&ヒープについて
- https://github.com/philip82148/leetcode-swejp/pull/3/files#r1853944201
- https://github.com/Yoshiki-Iwasa/Arai60/pull/42
- https://github.com/rihib/leetcode/pull/7
- https://github.com/rossy0213/leetcode/pull/23
- https://github.com/rossy0213/leetcode/pull/23#discussion_r1696208116
- https://github.com/fhiyo/leetcode/pull/48
- leftをexclusiveにするのも一つ
- setのドキュメント
- https://docs.python.org/3.12/library/stdtypes.html#set
- https://github.com/sakzk/leetcode/pull/3
- https://github.com/sakzk/leetcode/pull/3/files#r1591194013
- https://github.com/Mike0121/LeetCode/pull/21
- https://github.com/Exzrgs/LeetCode/pull/2
- https://github.com/thonda28/leetcode/pull/6
- https://github.com/SuperHotDogCat/coding-interview/pull/3
- https://github.com/nittoco/leetcode/pull/3
- ASCIIについて
- https://discordapp.com/channels/1084280443945353267/1198621745565937764/1211683153668866139
- https://github.com/t0d4/leetcode/pull/2
- https://github.com/shining-ai/leetcode/pull/48
- https://github.com/hayashi-ay/leetcode/pull/47
- https://discord.com/channels/1084280443945353267/1198621745565937764/1211678975156420678
- ASCIIの話
- https://github.com/usatie/leetcode/blob/main/Blind75/03.%20Longest%20Palindromic%20Substring/ans_01_20240126.cpp

全探索
```python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
def is_repeating(s: str) -> bool:
return len(set(s)) != len(s)

s_len = len(s)
longest_substring_len = 0
for left in range(s_len):
for right in range(left, s_len):
Comment on lines +93 to +94

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分なら文字ではなくインデックスであることを強調するために left_iright_i としますね。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#35 (comment)
このようなコメントをいただいた事があり、以降消すようにしています。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ハンガリアン記法的な話ですね

Comment on lines +93 to +94
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s_lenと変数を作るより普通にlen(s)のままの方がわかりやすく思います

sub_s = s[left:right + 1]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここでリストのコピーを作ることになるので非効率ではありますね

if not is_repeating(sub_s):
longest_substring_len = max(
longest_substring_len,
len(sub_s)
)

return longest_substring_len
```
思考ログ:
- 頭から抜けていた、良くない

出現回数管理
```python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
letter_to_count = {c: 0 for c in s}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultdict とか Counter を使いたくなります


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あまり意味のない空行のように思います

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

意味がないですね。
ありがとうございます。

left = 0
max_len = 0
for right in range(len(s)):
while letter_to_count[s[right]] > 0:
letter_to_count[s[left]] -= 1
left += 1

letter_to_count[s[right]] += 1
max_len = max(max_len, right - left + 1)
Comment on lines +120 to +121
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

細かいですが、自分ならこの2つの行逆にします。(for文の最後でrightが進むことに関係する部分は動かしたいため)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かにそうですね。
忘れそうだと思って先に書いてしまったんですかね。


return max_len
```
思考ログ:
- これはこれで素直だなと感じた

文字が登場した最後のインデックスを使う
```python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
left = 0
letter_to_last_index = {}
max_len = 0
for right in range(len(s)):
if s[right] in letter_to_last_index:
left = max(left, letter_to_last_index[s[right]] + 1)

max_len = max(max_len, right - left + 1)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最大の長さであることはは読んでいれば割とすぐわかる情報で、むしろresultの方が何についての最大の長さなのか関数名を見ればわかるので(関数名がはっきりしていたら)、個人的には好みです

letter_to_last_index[s[right]] = right

return max_len
```
思考ログ:
- ややテクニカルだが効率はいいなと感じた

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文字とインデックスの辞書を作成してそれを参照する方法なので、個人的にはそこまでテクニカルではなくオーソドックスな方法だと思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分には、最後に見たインデックス情報を活用するこの方法がすぐ出てきませんでした。。
現在のleftより前に戻らないようにする部分も初手でハンドリングできていたか怪しいです。

精進致します。

- leftを更新する際に現在のleftより前に戻らないようにすることを注意しないといけない

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私もハマりました

- ちゃんと脳内でシミュレート出来ていれば問題ないのかもしれないが、自分のシミュレータだとちょっと危なっかしいなと感じた

# Step3

かかった時間:4min

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これ 3 回やって 4 min ですかね?突っ込むほどのこともないですが、もうちょっと早くなる気もしており、いや別に早くすることが目的ではないんですが、なにか迷いがあるのかなあ、と思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かにと思い、解き直してみましたが、2分程かかりました。
割と解きながら他の選択肢について思い出していたりすることがあるので、それで余計な時間を使ったのかもしれません。


```python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
letter_to_last_index = {}
left = 0
max_len = 0
for right in range(len(s)):
if s[right] in letter_to_last_index:
left = max(left, letter_to_last_index[s[right]] + 1)

max_len = max(max_len, right - left + 1)
letter_to_last_index[s[right]] = right

return max_len
```
思考ログ:
- 情報の活用の仕方に学びがあったので、こちらの解き方にした
- step2から少し日が経って書いたが、ほぼ同じものが出てきて、改めてそういうものなんだなと感じた
- 序盤の変数定義の並びが変わっているのは、この方法で解こうという思いが強かったからかもしれない

# Step4

```python
```
思考ログ: