Conversation
| - cf. https://docs.python.org/ja/3.13/library/stdtypes.html#str.startswith | ||
| * https://github.com/fuga-98/arai60/blob/9e0b4995439f57158f4dc9aa4ad6ff7d1bb8d11a/139.%20Word%20Break.md | ||
| - DFSを使った解法 | ||
| - dequeの代わりに `list` を使っていて `pop()` を `-1` にしているので少し分かりづらいと思った |
There was a problem hiding this comment.
pop() は元のリストの末尾の要素を削除してからその要素を返し、-1(スライス)は元のリストを変更せずに元のリストの末尾の要素の浅いコピーを返す認識です。
.pop() を単純に [-1] に置き換えても正常に動かないですね。
申し訳ありません、私の勘違いでした。
There was a problem hiding this comment.
これは練習なのでどんどん間違えて大丈夫だと思います!
ここらへんを読むと良いかもしれません。
https://docs.python.org/ja/3.13/library/stdtypes.html#mutable-sequence-types
| if start_index == len(s): | ||
| return True | ||
|
|
||
| for end_index in range(start_index + 1, len(s) + 1): |
There was a problem hiding this comment.
len(s) + 1の+1は不要そうに見えます。末尾のindex はlen(s) - 1なので。
スライスは範囲外にアクセスしてもエラーを出さないです。
https://docs.python.org/ja/3.13/tutorial/introduction.html
| if not reachable[start_index]: | ||
| continue | ||
| for end_index in range(start_index + 1, s_size + 1): | ||
| if reachable[start_index] and s[start_index:end_index] in word_dict: |
| - cf. https://docs.python.org/ja/3.13/library/functools.html#functools.lru_cache | ||
| * 短絡評価で副作用のある関数(再帰)があって読みにくい | ||
| * `s` のスライスが分かりにくい | ||
| * ベースケース `i < 0` が直観的でない |
| while start_index < len(s): | ||
| for word in wordDict: | ||
| end_index = start_index + len(word) | ||
| if s[start_index:end_index] == word: |
There was a problem hiding this comment.
スライスでコピーを毎回作っている点が気になりました。
if s.find(word, start_index, end_index) != -1:とも書けそうだなと思いました。どれくらい処理が軽くなるかは調べておりません。また、 find() をこの用途で使うのはあまり見ないとも思いました。
| def wordBreak(self, s: str, wordDict: List[str]) -> bool: | ||
| @cache | ||
| def can_break(i): | ||
| if i < 0: |
There was a problem hiding this comment.
負の場合にも True を返している点に違和感を感じました。
if i == 0:
return True
```
として、文字列の開始地点のみ True を返してあげるようにしたほうがシンプルだと思いました。| return True | ||
|
|
||
| for word in wordDict: | ||
| if s[i - len(word) + 1 : i + 1] == word and can_break(i - len(word)): |
There was a problem hiding this comment.
i - len(word) + 1 の部分が負になった場合の挙動が分かりにくく感じました。
>>> a = "0123456789"
>>> a[-2:5]
''
>>> a[-2:9]
'8'文字数が違うのでたまたま False になっているように感じました。
if i < len(word):
continueを入れてあげたほうが理解しやすくなると思いました。
| return True | ||
|
|
||
| for word in wordDict: | ||
| if s[i - len(word) + 1 : i + 1] == word and can_break(i - len(word)): |
There was a problem hiding this comment.
if s[i - len(word) + 1 : i + 1] == word:
return can_break(i - len(word))のほうがシンプルだと思いました。
| * `s` のスライスが分かりにくい | ||
| * ベースケース `i < 0` が直観的でない | ||
| * 実行時間: 7ms | ||
| - 大して変わらなかった |
There was a problem hiding this comment.
LeetCode の実行時間は計測誤差が大きいため、あまり信じすぎないほうがよいと思います。もしどうしても正確に実行時間を計測したい場合は、ローカルで複数回実行し、中央値を取ったほうがよいと思います。
また、実行時間を短くする必要がある場合は、 C++ 等のより高速な言語の仕様を検討することをお勧めいたします。
| class Solution: | ||
| def wordBreak(self, s: str, wordDict: List[str]) -> bool: | ||
| s_size = len(s) | ||
| reachable = [False] * (s_size + 1) |
There was a problem hiding this comment.
好みの問題かもしれません。
変数名から、中身の型が予測しづらいと感じました。
is_reachableはどうでしょうか?
There was a problem hiding this comment.
is_reachable は関数名にも見えるため、微妙なところです。 reachable で「到達可能かどうか?」というニュアンスがあるため、中に bool 値が含まれていると読み取れるとも思います。
139. Word Break
次回予告: 141. Linked List Cycle