Skip to content

Create Word Break.md#8

Open
yakataN wants to merge 2 commits into
mainfrom
word-break
Open

Create Word Break.md#8
yakataN wants to merge 2 commits into
mainfrom
word-break

Conversation

@yakataN
Copy link
Copy Markdown
Owner

@yakataN yakataN commented Aug 18, 2025

Comment thread Word Break/Word Break.md
return rec(0)
```

おそらくあってはいるが、スライスでコピーが作成されるため、大きな例でTLEを起こす。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

a と aa で aaa....aab を割ってみましょう。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

この例はすでに到達可能なことがわかっているものを再計算するのは筋が悪いという意味で捉えればよいのでしょうか。

Comment thread Word Break/Word Break.md
return True

for word in wordDict:
if s[index:index+len(word)] == word:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

https://docs.python.org/3/library/stdtypes.html#str.startswith
startswith のドキュメントを読みましょう。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

存在知らなかったのも、調べなかったのも罪が重いですね……。

 if s[index:index+len(word)] == word:

if s.startswith(word, i):

に置換してACし直しました。(当然ながら早くなりました)

Comment thread Word Break/Word Break.md
```python3
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
# dp[index] = is_reached?(True | False)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dp という名前は好まれません。上から見ていって何か分からないので。
https://discord.com/channels/1084280443945353267/1247673286503039020/1254123432438927432

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ご指摘ありがとうございます。is_prefix_formatableに変更しました。(step4に記載)

Comment thread Word Break/Word Break.md
return False
```

##### メモ化再帰で解き直す
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

functools.cache を確認しておいてください。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

確認しました。メモ化が公式で提供されているんですね。
時々は公式Docs見直さないとだめですね…

Comment thread Word Break/Word Break.md

##### やったうえでの感想

- DPのほうが見通しよいし、読みやすい
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

再帰の場合ももう少し整理すると見通しよく書けます。他の人のPRをもう少し読んでみると良いと思いました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

直してみました。(step4に追記)
メモ化がfunctools.cacheに吸収されたこともあって、だいぶ見通しよくなりました。

Comment thread Word Break/Word Break.md
```python3
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
start_index_to_match_lengths = dict()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

手作業でやる場合このような処理はしない気がしていまして、DP の場合と同様に各 i に対して各 word が当てはまるかを確かめる方が直感的に思いました。

Comment thread Word Break/Word Break.md

def rec(index: int) -> bool:
if index in memo:
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

変数名 memo だと return memo[index] であることを想定して読むと思います。

Comment thread Word Break/Word Break.md

if dp[len(s)]:
return True
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

return dp[len(s)] でよいでしょうか?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dp[-1] でもいいかもしれません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。直接return するほうが見通しよいですね。配列のマイナスインデックスでこういうときに使うんですね。機能として知っていても有効に使えたことはありませんでしたので、勉強になります。

Comment thread Word Break/Word Break.md
return False

return _rec(0)
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

下のコードより上のコードの方が読みやすいです。
関数内関数は先頭に_をつけなくても良いと思います。
メソッドで外部から呼ばれることを想定しない場合は先頭に_をつける場合があります。
http://google.github.io/styleguide/pyguide.html#3162-naming-conventions
関数内関数なのでそこまでこだわりませんが、rec よりも良い名前がつけられると読みやすくなると思いました。

Comment thread Word Break/Word Break.md
if s.startswith(word, i):
is_prefix_formatable[i+len(word)] = True

return is_prefix_formatable[len(s)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

よいと思います。細かいですが関数名にあわせてformatableはbreakableとした方が分かりやすいと思いました。

Comment thread Word Break/Word Break.md
def _rec(index: int) -> bool:
if index == len(s):
return True
return any(s.startswith(word, index) and _rec(index + len(word)) for word in wordDict)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

個人的にはif index > len(s): return falseを入れたほうが良いのではないかと思いました。
s.startswith(word, index)falseだった段階で_rec(index + len(word)が評価されずにs.startswith(word, index) and _rec(index + len(word))falseであるという判断が下されるので大丈夫なんですが、一見するとindexlen(s)を過ぎた後も延々と_recが呼び出されてしまうんじゃないかとちょっと不安になったので)

Comment thread Word Break/Word Break.md
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
@functools.cache
def _rec(index: int) -> bool:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

_rec という関数名ですが、内部実装を表す名前であって、個人的には関数内関数でもあまり使わないほうがよいかなと感じます。代替案としては word_break_helper (or *_auxiliary) などでしょうか。

Comment thread Word Break/Word Break.md
def _rec(index: int) -> bool:
if index == len(s):
return True
return any(s.startswith(word, index) and _rec(index + len(word)) for word in wordDict)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

個人的に、内包表記よりも (上のように) ループとフラグを使って書きたくなります。Pythonic ではあるのですが、内包表記はもっと簡便な処理に使いたいです。

Comment thread Word Break/Word Break.md
```python3
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
is_prefix_formatable = [False] * (len(s)+1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

スペースを空けるのが一般的かと思います。

is_prefix_formatable = [False] * (len(s) + 1)
is_prefix_formatable[i + len(word)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PEP8 のおすすめは開けないんですが、どちらでもいいかと思います。
https://peps.python.org/pep-0008/#other-recommendations
Google Python はどちらでもよいです。Google C++ は開けるんだったかと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

演算子の周りのスペースの話です。
https://google.github.io/styleguide/pyguide.html#36-whitespace

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

おっしゃる通りですね。失礼しました!

Comment thread Word Break/Word Break.md
```python3
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
is_prefix_formatable = [False] * (len(s)+1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

英語のスペル的には formattable ですね。ただ別途コメントがある通り、私も breakable の方が良いと思います。format と言われると f-string のようなものを連想します。

Comment thread Word Break/Word Break.md
start_index_to_match_lengths[i] = set()
start_index_to_match_lengths[i].add(len(word))

memo = dict()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dp 同様、memo よりも説明的な名前が良いと感じます。index_to_breakable などはどうでしょう。

Comment thread Word Break/Word Break.md
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
@functools.cache
def _rec(index: int) -> bool:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

inner fuction の関数名の先頭には _ は付けないことが多いと思います。 non-public なメソッドやインスタンス変数のほうには付けることが多いと思います。

参考までにスタイルガイドへのリンクを貼ります。

https://peps.python.org/pep-0008/#method-names-and-instance-variables

Use one leading underscore only for non-public methods and instance variables.

https://google.github.io/styleguide/pyguide.html#3162-naming-conventions

Prepending a single underscore (_) has some support for protecting module variables and functions (linters will flag protected member access).

上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

関数内関数とnon-publicな関数の区別がついていませんでした。勉強になりました。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants