Problem
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> … -> sk such that:
Every adjacent pair of words differs by a single letter.
Every si for 1 <= i <= k is in wordList. Note that beginWord does not need to be in wordList.
sk == endWord
Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord, or 0 if no such sequence exists.
Constraints:
- 1 <= beginWord.length <= 10
- endWord.length == beginWord.length
- 1 <= wordList.length <= 5000
- wordList[i].length == beginWord.length
- beginWord, endWord, and wordList[i] consist of lowercase English letters.
- beginWord != endWord
- All the words in wordList are unique.
Algorithm
Use trie as to save and search the words and then use bfs to find the shortest path.
Code
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
sLen = len(wordList)
find_end = 0
find_begin = 0
wLen = [0] * (sLen+1)
for i in range(sLen):
if wordList[i] == endWord:
find_end = i + 1
if wordList[i] == beginWord:
find_begin = i + 1
wLen[i+1] = len(wordList[i])
if not find_end:
return 0
if not find_begin:
wordList = [beginWord] + wordList[:]
else:
wordList = [""] + wordList[:]
# construct trie
class trie:
def __init__(self):
self.val = 0
self.next = [None] * 26
bLen = len(beginWord)
root = trie()
for i in range(1, sLen+1):
if wLen[i] != bLen:
continue
p = root
for k in range(bLen):
p_id = ord(wordList[i][k]) - ord('a')
if not p.next[p_id]:
p.next[p_id] = trie()
p = p.next[p_id]
p.val = i
# bfs for shortest path
find = [0] * (sLen + 1)
find[find_begin] = 1
head, tail = 0, 1
Q = [find_begin] * (sLen + 1)
Step = [1] * (sLen + 1)
while head < tail:
now = Q[head]
for i in range(bLen):
for j in range(26):
new = wordList[now][:i] + chr(j+ord('a')) + wordList[now][i+1:]
p = root
save = [' '] * bLen
for k in range(bLen):
p_id = ord(new[k]) - ord('a')
save[k] = chr(p_id + ord('a'))
if p.next[p_id]:
p = p.next[p_id]
else:
p = None
break
if p and p.val:
if p.val == find_end:
return Step[now] + 1
if not find[p.val]:
Q[tail] = p.val
find[p.val] = 1
Step[p.val] = Step[now] + 1
tail += 1
head += 1
return 0