Conversation
| def is_connectable(s1: str, s2: str) -> bool: | ||
| count = 0 | ||
| for i in range(len(s1)): | ||
| if s1[i] != s2[i]: | ||
| count += 1 | ||
| return count == 1 |
| tail_word, sequence_length = queue.popleft() | ||
| for key in word_to_keys[tail_word]: | ||
| for word in key_to_words[key]: | ||
| if word not in seen: | ||
| if word == endWord: | ||
| return sequence_length + 1 |
There was a problem hiding this comment.
ここのネストがかなり深くなっていくので、tail_wordを引数として、次のwordを生成する関数があってもいいのではと感じました。以下みたいな感じでしょうか?
def generate_next_word(word: str, seen: set[str]) -> Iterator[str]:
for key in word_to_keys[word]:
for next_word in key_to_words[key]:
if next_word in seen:
continue
yield next_wordThere was a problem hiding this comment.
wordがendWordの時すぐreturnすればネストを一つ消せることに気づきましたが, それでもまだ長い気がするのでyieldを使うことにします。
while queue:
tail_word, sequence_length = queue.popleft()
for key in word_to_keys[tail_word]:
for word in key_to_words[key]:
if word == endWord:
return sequence_length + 1
if word not in seen:
queue.append((word, sequence_length + 1))
seen.add(word)| def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: | ||
| wordList = set(wordList) | ||
| queue = deque([[beginWord, 1]]) | ||
| lower_characters = 'abcdefghijklmnopqrstuvwxyz' |
There was a problem hiding this comment.
string.ascii_lowercaseを使うのもありかと思います。字数はそれほど変わりませんが、タイプミスや入れ忘れは減ると思います。
| queue.append((word, sequence_length + 1)) | ||
| seen.add(word) | ||
| return 0 | ||
| # 書いてから思ったけど1に等しいかどうかで判断する方が綺麗かも |
| class Solution: | ||
| def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: | ||
| for word in wordList: | ||
| if word == endWord: # ここ, if endWord not in wordListで効率化できるな |
There was a problem hiding this comment.
pythonのリストのin, not inについてはネイティブコードで実装されているので、速度的にも入力文字数という意味でもnot inとした方が良さそうです。
https://github.com/python/cpython/blob/main/Objects/listobject.c#L616
| key_to_words = defaultdict(list) | ||
| word_to_keys = defaultdict(list) |
| word_diff_count = 0 | ||
| for i in range(len(s1)): | ||
| if s1[i] != s2[i]: | ||
| word_diff_count += 1 |
There was a problem hiding this comment.
この問題で必要なのって、単語が隣接しているかどうかなので、diff_countについて2以上を数える必要がなくなり、そのようなロジックを組み込めるとそのぶんシンプルにできそうです。
| if tail_word == endWord: | ||
| return sequence_length | ||
| for word in available_words: | ||
| if calc_word_diff(tail_word, word) == 1: |
There was a problem hiding this comment.
ネストが深すぎるので、ここを反転させてearly continueみたいな感じでやれると読みやすくできそうです。
| @@ -0,0 +1,69 @@ | |||
| # 単純にBFSをしてtime limit overしたもの, そりゃそうだろうなという感じの時間計算量 | |||
There was a problem hiding this comment.
時間計算量を求めることはできますか?また、そこからおおよその実行時間を推定できますか?
There was a problem hiding this comment.
この解答だとqueue.append((word, next_available_words, sequence_length + 1))で使える単語も保持していて遠回りも含めた全部のルートを考えてしまっているので, 大雑把には最悪の場合n = wordList.lengthとした時n×(n-1)×(n-2)×...×1となってしまい, O(n!)かかります。Pythonは1秒10^6stepほどだった気がするので今回wordList.length <=5000であり, スターリング公式でn!≒n^(n+1/2) / e^nとして考えるとn=5000を代入して1831^5000 × 70 / 10^6≒(2000)^5000×70/10^6=7×10^16495 sec程度かかる気がします。(2^10≒10^3を用いて計算)
There was a problem hiding this comment.
あ、いやcalc_word_diffにword.length分かかるので今回word.length<=10なので7×10^16496 secでしょうか
There was a problem hiding this comment.
n×(n-1)×(n-2)×...×1となってしまい
ここの部分に違和感を感じました。単語 S1 → S2 → S3 → ... → Sn と遷移して endWord にたどり着く場合、 endWord に近づく遷移と遠ざかる遷移があります。遷移は n 回行われますので、多めに見積もって 2^n に比例した個数の状態が保持されます。また wordList のコピーを毎回作っていますので、 2^n * n になると思います。 n = 5000 を代入すると、 log_{10}2 = 0.3 として、 2^5000 * 5000 ≒ 10^1500 * 5000 = 5.0 * 10^1503 くらいになると思います。
単語 S1 → S2 → S3 → ... → Sn と遷移して endWord にたどり着くような入力を意図して作れるかは未検討です。
There was a problem hiding this comment.
ちょっと実験してみました。
begin: hot, wordList: [lot, got, cot, cog], end: cogで少し樹形図書いてみたら9ルート出てきて確かに2^4のほうが4!よりは抑えられている気がしました。ありがとうございます。
| word_diff_count += 1 | ||
| return word_diff_count | ||
|
|
||
| word_graph = defaultdict(list) |
There was a problem hiding this comment.
グラフの中に入れる要素を単語本体ではなく wordList 内のインデックスとすることで、処理を少し軽くすることができるかもしれません。
| key = (word[:i], word[i + 1:]) | ||
| key_to_words[key].append(word) | ||
| word_to_keys[word].append(key) | ||
|
|
問題
https://leetcode.com/problems/word-ladder/description/