Skip to content

Conversation

@skypenguins
Copy link
Owner

139. Word Break

次回予告: 141. Linked List Cycle

@skypenguins skypenguins self-assigned this Jun 26, 2025
- 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` にしているので少し分かりづらいと思った
Copy link

Choose a reason for hiding this comment

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

確認ですが、popと-1の違いはわかりますか。

Copy link
Owner Author

Choose a reason for hiding this comment

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

pop() は元のリストの末尾の要素を削除してからその要素を返し、-1(スライス)は元のリストを変更せずに元のリストの末尾の要素の浅いコピーを返す認識です。
.pop() を単純に [-1] に置き換えても正常に動かないですね。
申し訳ありません、私の勘違いでした。

Copy link

Choose a reason for hiding this comment

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

これは練習なのでどんどん間違えて大丈夫だと思います!
ここらへんを読むと良いかもしれません。
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):
Copy link

Choose a reason for hiding this comment

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

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:

Choose a reason for hiding this comment

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

性質の違う条件はif文を分けたいと思いました。

- cf. https://docs.python.org/ja/3.13/library/functools.html#functools.lru_cache
* 短絡評価で副作用のある関数(再帰)があって読みにくい
* `s` のスライスが分かりにくい
* ベースケース `i < 0` が直観的でない

Choose a reason for hiding this comment

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

コードないにコメントを入れてもいいのかなとお思いました。

while start_index < len(s):
for word in wordDict:
end_index = start_index + len(word)
if s[start_index:end_index] == word:
Copy link

Choose a reason for hiding this comment

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

スライスでコピーを毎回作っている点が気になりました。

if s.find(word, start_index, end_index) != -1:

とも書けそうだなと思いました。どれくらい処理が軽くなるかは調べておりません。また、 find() をこの用途で使うのはあまり見ないとも思いました。

Copy link

Choose a reason for hiding this comment

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

startswith がありますね。

def wordBreak(self, s: str, wordDict: List[str]) -> bool:
@cache
def can_break(i):
if i < 0:
Copy link

Choose a reason for hiding this comment

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

負の場合にも 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)):
Copy link

Choose a reason for hiding this comment

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

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)):
Copy link

Choose a reason for hiding this comment

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

if s[i - len(word) + 1 : i + 1] == word:
    return can_break(i - len(word))

のほうがシンプルだと思いました。

* `s` のスライスが分かりにくい
* ベースケース `i < 0` が直観的でない
* 実行時間: 7ms
- 大して変わらなかった
Copy link

Choose a reason for hiding this comment

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

LeetCode の実行時間は計測誤差が大きいため、あまり信じすぎないほうがよいと思います。もしどうしても正確に実行時間を計測したい場合は、ローカルで複数回実行し、中央値を取ったほうがよいと思います。
また、実行時間を短くする必要がある場合は、 C++ 等のより高速な言語の仕様を検討することをお勧めいたします。

class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
s_size = len(s)
reachable = [False] * (s_size + 1)

Choose a reason for hiding this comment

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

好みの問題かもしれません。
変数名から、中身の型が予測しづらいと感じました。
is_reachableはどうでしょうか?

Copy link

Choose a reason for hiding this comment

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

is_reachable は関数名にも見えるため、微妙なところです。 reachable で「到達可能かどうか?」というニュアンスがあるため、中に bool 値が含まれていると読み取れるとも思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants