126.ワードソリティア
2つの単語(beginWordとendWord)と辞書のwordListが与えられた場合、beginWordからendWordへの最短の変換シーケンスをすべて見つけます。変換は次のルールに従う必要があります。変換ごとに変更できる文字は1文字のみです。変換後に取得される単語は、辞書内の単語である必要があります。説明:そのような変換シーケンスがない場合は、空のリストが返されます。すべての単語の長さは同じです。すべての単語は小文字のみで構成されています。辞書に重複する単語はありません。beginWordとendWordは空ではなく、同じではないと想定できます。
示例 1: 输入: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出: [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ] 示例 2: 输入: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] 输出: []
説明:endWord "cog"が辞書にないため、要件を満たす変換シーケンスがありません。
コード
1まず、最後の最終バージョンは実際には上司のコードに基づいています
class Solution2:
def findLadders(self, beginWord, endWord, wordList):
if endWord not in wordList:
return 0
s1 = {beginWord}
s2 = {endWord}
step = 0
while s1 and s2:
if len(s1)>len(s2):s1, s2 = s2, s1
step += 1
s = set()
for preword in s1:
n = len(preword)
next_words = [preword[:i] + chr(j) + preword[i+1:] for j in range(97, 123) for i in range(n)]
for word in next_words:
if word in s2:
return step + 1
if word not in wordList:
continue
wordList.remove(word)
s.add(word)
s1 = s
return 0
それから私の精神的な旅について話します
最初は、この質問がわからないことに気づき、質問するのが面倒でした。。。パスの問題で少し途方に暮れるかもしれません。。。後で、問題を解決するというアイデアを簡単に見てみました。マッピングの語彙を置き換えるロジックがあります。たとえば、key = "a * b"、value = 'a * b'を満たす辞書内の単語です。 、*は任意の文字を意味します。つまり、get別の文字の単語は何ですか。
class Solution:
def get_word_dic(self, wordList):
dic = dict()
for word in wordList:
for i in range(len(word)):
mark = word[:i] + '*' + word[i + 1:]
dic.setdefault(mark, [])
if word not in dic[mark]:
dic[mark].append(word)
return dic
def find(self, pre_word_lists, endWord, dic):
if len(pre_word_lists)==0:
return []
res = []
level1_word_lists = []
for pre_word_list in pre_word_lists:
beginWord = pre_word_list[-1]
level1_words = set()
for i in range(len(beginWord)):
mark = beginWord[:i] + '*' + beginWord[i + 1:]
if mark not in dic:
continue
if endWord in dic[mark]:
res.append(pre_word_list + [endWord])
level1_words.update([x for x in dic[mark] if x not in pre_word_list])
level1_word_lists.extend([pre_word_list + [x] for x in level1_words])
if len(res) > 0:
return res
paths = self.find(level1_word_lists, endWord, dic)
if len(paths) > 0:
return paths
return []
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
if endWord not in wordList:
return 0
dic = self.get_word_dic(wordList)
paths = self.find([[beginWord]], endWord, dic)
if len(paths)==0:
return 0
return len(paths[0])
タイムアウトになり、ダニエルの考えを見てトップコードを書きましたが、コードがどこで遅いのかを知りたくありませんでした。
双方向の問題については言うまでもなく、それは大きな影響を与えるはずですが、時間を測定した後、len(s1)> len(s2):s1、s2 = s2、s1の場合の双方向の文はまだ比較されます。鉱山ははるかに高速です。
毎回辞書から検索して、トップコードのaz置換のロジックに変更するのに時間がかかるかどうかを確認するのは時間がかかりますが、送信後もタイムアウトになります。
他の場所を見ると、辞書の削除の問題に加えて、辞書の削除の操作、次のコード、送信はまだタイムアウトになりますが、より多くのテストケースに合格したと感じています
class Solution:
def find(self, pre_word_lists, endWord, wordList):
if len(pre_word_lists)==0:
return 0
level1_word_lists = []
for pre_word_list in pre_word_lists:
beginWord = pre_word_list[-1]
nextword = []
for i in range(len(beginWord)):
for j in range(97, 123):
word = beginWord[:i] + chr(j) + beginWord[i + 1:]
if word in wordList and word not in pre_word_list:
nextword.append(word)
wordList.remove(word)
if endWord in nextword:
return len(pre_word_list + [endWord])
level1_word_lists.extend([pre_word_list + [x] for x in nextword])
return self.find(level1_word_lists, endWord, wordList)
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
if endWord not in wordList:
return 0
return self.find([[beginWord]], endWord, wordList)
結局、双方向に変更する必要があることがわかりました。そうしないと、辞書が長すぎてパスが多すぎます。それでも、爆発的なパス検索の問題が発生します...