Conversation
| num_words += 1 | ||
| return 0 | ||
|
|
||
| def _getNextWords(self, word: str, words: set[str]) -> Generator[str, None, None]: |
There was a problem hiding this comment.
自分で書く関数名は、 3rd のように lower snake で統一してよいと思います。
| def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: | ||
| words = set(wordList) | ||
| num_words = 1 | ||
| word_queue = deque([beginWord]) |
There was a problem hiding this comment.
変数名の queue は型と情報が重複しているため、不要だと思います。 3rd のように words next_words のほうが良いと思います。ただ、この命名も人によっては違和感を感じるかもしれません。自分は幅優先探索を書くときは、 frontier explorered という単語を使いますが、少数派かもしれません。
また、幅優先探索を書くとき、この解答のようにキューを 2 つ用意する実装方法も良いと思います。一方、キューは 1 つだけ用意し、先頭から取り出す、末尾に入れるという形で実装することもあります。その場合、キューまたは別の領域に、何回辿ったかを表す整数を保存しておく必要があります。個人的には最近はこちらの書き方で書くことが多いです。
There was a problem hiding this comment.
自分は幅優先探索を書くときは、 frontier explorered という単語を使いますが、少数派かもしれません。
ダイクストラのfrontierのイメージですかね。_queueとsuffixを付けたのは他の変数でwordsという名前を使ってたので付けました。今回みたいな仕方ないので_queue付ける、みたいなときの別の選択肢として良いかもと思いました。
| for next_word in self._getNextWords(word, words): | ||
| next_word_queue.append(next_word) |
There was a problem hiding this comment.
next_word_queue.extend(self._getNextWords(word, words)) でよいと思います。
| return 0 | ||
|
|
||
| def _getNextWords(self, word: str, words: set[str]) -> Generator[str, None, None]: | ||
| for i, original_ch in enumerate(word): |
There was a problem hiding this comment.
自分が書く場合は、 words でループを回し、 word と 1 文字違いかどうかを調べると思います。。ただし、 1 <= wordList.length <= 5000 のため Python だと TLE になると思います。自分の場合は C++ を使います。
There was a problem hiding this comment.
問題の制約が 1 <= beginWord.length <= 10 なので、最初は O(len(wordList)^2) でもいいがそこから制約が厳しくなったときに高速化する方法はあるか、という話に繋がりそうな気はしますね。言語を変えて定数倍高速化するという方法は一つではあるでしょうが、例えばここだけC++で他多言語みたいな状態にすると保守性は下がりそうな気はします
| continue | ||
| new_word = f'{word[:i]}{ch}{word[i + 1:]}' | ||
| if new_word in words: | ||
| words.remove(new_word) |
There was a problem hiding this comment.
入力データを変更している点に違和感を感じます。自分だったら、使用済みの単語を表す set() を作ると思います。
| class Solution: | ||
| def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: | ||
| wordList.append(beginWord) | ||
| adjacentList = self._makeAdjacentList(wordList) |
There was a problem hiding this comment.
自分で定義する変数名は、 3rd のように lower snake でよいと思います。
|
|
||
|
|
||
| ```py | ||
| class Solution: |
There was a problem hiding this comment.
自分はこちらの解法を先に思い付きました。ただ、 Python で O(len(wordList) ** 2) が通ると思えません。自分だったらこちらの解法を C++ で書くと思います。
| endWordがwordListになかったら0を返すようにしている。高速化したくなったらやるかも、くらいの感覚。 | ||
|
|
||
| i番目の文字が任意となることを表すパターンをkeyとして、そのパターンに合致するwordの集合をvalueとする辞書を作る。 | ||
| ちょっとネストが深い。 |
There was a problem hiding this comment.
https://discord.com/channels/1084280443945353267/1200089668901937312/1216123084889788486
https://cs.stackexchange.com/questions/93467/data-structure-or-algorithm-for-quickly-finding-differences-between-strings
頭から半分または尻尾から半分が一致しているはずなので、それでバケットを作ってバケット内でのみ比較すればいいというやりかたもありますね。(編集距離が1であるかの確認に、頭から何文字一致していて、尻尾から何文字一致しているかを足してやればいいという方法をどっかで使ったことあります。)
| nextWordIndexes = deque() | ||
| while wordIndexes: | ||
| wordIndex = wordIndexes.popleft() | ||
| used[wordIndex] = True |
There was a problem hiding this comment.
訪れたことを記録するタイミングは、nextWordIndexes.append(nextWordIndex) と同時にする方が好みです。
https://leetcode.com/problems/word-ladder/description/