Conversation
There was a problem hiding this comment.
nit sol1.py がTLEする方で、sol1_failed.py がパスする方に見受けられるので、ファイル名が逆かもしれません。
| stripped_sub_strs = [] | ||
| for word in wordDict: | ||
| if s.startswith(word): | ||
| stripped_sub_strs.append(s[len(word) :]) |
There was a problem hiding this comment.
str.strip() をするのかと変数名を見て思いましたが、いわゆる strip 処理を行っていなさそうなので、単に sub_strings でいいかなと思います。
| if i == len_target: | ||
| return True | ||
| for word in wordDict: | ||
| if s.startswith(word, i) and can_break(i + len(word)): |
There was a problem hiding this comment.
なるほど、部分文字列をわざわざ作らなくても startswith でいけるんですね、勉強になります 👀
| > は、 | ||
| > "a" * 2 と "a" * 4 で表せないので、単純なバックトラックでは失敗するというのが予想です。 | ||
|
|
||
| 「正規表現で書けるからO(n)」はあくまでwordDictが定数のときの話だろう。ただこの考えは持っておきたい。 |
There was a problem hiding this comment.
あくまでwordDictが定数のとき
これはどういう意味でしょうか。listの要素が固定されている、という意味であれば、関数が呼び出されたタイミングで固定されていると思いました。
There was a problem hiding this comment.
計算量の見積もりにおいてて定数とみなされている、という意味です。
もし定数でなければ、正規表現を受理するオートマトンの構築自体の時間も考える必要があると思いました。
| @functools.cache | ||
| def can_break(i) -> bool: | ||
| if i == len_target: | ||
| return True |
There was a problem hiding this comment.
個人的には冗長な説明変数に思いました。
| return True | |
| @functools.cache | |
| def can_break(i) -> bool: | |
| if i == len(s): |
There was a problem hiding this comment.
ほぼ変わらないと思いますが、実行時間が定数倍減少すると思うので、このままにしておこうと思います。
| len_target = len(s) | ||
|
|
||
| @functools.cache | ||
| def can_break(i) -> bool: |
There was a problem hiding this comment.
関数の中身まで読まないと i の意味が分からないので(呼び出し方で予測はできますが)、前説してあると丁寧です。
| def can_break(i) -> bool: | |
| def can_break(i: int) -> bool: | |
| """returns whether s[i:] can be broken.""" |
There was a problem hiding this comment.
なるほど。たしかに引数のiが何を指しているのかわかりませんね。採用させていただきます。
| len_target = len(s) | ||
|
|
||
| @functools.cache | ||
| def can_break(i) -> bool: |
There was a problem hiding this comment.
iが何を意味するのかをコードから推理する必要があったので,start_posあたりにすると良いかもしれません.
There was a problem hiding this comment.
みていただいた二人の目に留まったということは、良いコードではないのですね。
start_posにさせていただきます。
| frontier = [0] | ||
| visited = {0} | ||
| while frontier: | ||
| position = frontier.pop() |
| - n = |s|, m = len(wordDict), l = max([len(word) for word in wordDoct])とする | ||
|
|
||
| ### sol1.py | ||
| - 時間 O(nml): can_breakはメモ化しているので高々O(n)回呼び出される、それぞれの関数内でwordDict内全ての文字列比較をするので O(ml) |
There was a problem hiding this comment.
計算量から具体的な計算時間の目安を見積もると実行前にTLEに気付けるようになるかもしれません.
見積もり方はこちらが参考になります.
今回の場合ですと,
ですから,Pythonが 1e6 ~ 1e7 steps/sec であることを踏まえると最大で 1 ~ 10秒 程度かかる,と言う見積もりになるかと思います.
There was a problem hiding this comment.
ありがとうございます、参考になりました。自分で見積もるくせをつけておきたいですね。
|
|
||
| @dataclasses.dataclass | ||
| class TrieNode: | ||
| children: Dict[str, TrieNode] = dataclasses.field(default_factory=dict) |
There was a problem hiding this comment.
別にList[TrieNode]を用意し,辞書自体はDict[str, int]としておいて,map先のintを使ってList[TrieNode]からTrieNodeを取り出すようにすると早いかもしれない,と言う議論がありました(cf).
Pythonのリストは動的配列だったはずなので,同様の議論が成り立つと思いますが,インタプリタ言語である以上ボトルネックがC++と異なるので,可読性なども考慮した上でやる価値があるかは不明です...
There was a problem hiding this comment.
なるほど、C++の場合にはキャッシュヒットが増えそうなのは理解ができました。
Pythonで行う必要性があるのかは確かに疑問ですね。
このようなことも考えながらコードを書けるようになりたいです。
|
|
||
| class Solution: | ||
| def wordBreak(self, s: str, wordDict: List[str]) -> bool: | ||
| len_target = len(s) |
There was a problem hiding this comment.
好みの問題でしょうが,len(s)のままで良いと思います.情報量が変わらず,長さも短くなるわけではないので.
| root = TrieNode() | ||
| max_len_of_wordDict = 0 | ||
| for word in wordDict: | ||
| max_len_of_wordDict = max(max_len_of_wordDict, len(w)) |
There was a problem hiding this comment.
個人的にはmax_len_of_wordDictを求めるロジックはTrie木を作るロジックと別物であるので分離するのが好みです.
このfor文の後で,
max_len_wordDict = max(map(len, wordDict), default=0)や
max_len_wordDict = max(len(word) for word in wordDict)などとするのはいかがでしょうか.
There was a problem hiding this comment.
後の方を採用しました(しかもw と word が間違っていましたね)
|
|
||
| 「正規表現で書けるからO(n)」はあくまでwordDictが定数のときの話だろう。ただこの考えは持っておきたい。 | ||
|
|
||
| > というわけで、先頭から DP が"模範解答"だろうな、とは思います。 |
There was a problem hiding this comment.
背景として、 Vitabi のアルゴリズムがありそうな気がしました。
https://ja.wikipedia.org/wiki/%E3%83%93%E3%82%BF%E3%83%93%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0
There was a problem hiding this comment.
最大確率を求めるわけではないのでやや疑問ですが、たしかにインデックスを状態としたDPを行うのは似ているのかもしれません
https://leetcode.com/problems/word-break/description/