本题解题思路中用到了哈希、堆栈的知识点。
2、题目
Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time.
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
UPDATE (2017/1/20):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.
3、审题
已知条件:起始单词、目的单词、词典
动作:起始单词每次变化其中一个字母,经过N次变化后,变为目的单词
求:从起始单词变化为目的单词的最小路径(N最小)
4、解题思路
以题目中的example来讲解思路。
本题的基本思路可以用暴力破解法,用多叉树的思路,找到所有从起始单词到目的单词的路径,再比较取最短路径即可。
但该方法空间复杂度消耗太大(需保存所有的多叉树路径),舍弃。
=> 本题用堆栈、哈希的思路来求解。
Step1:从起始单词到目的单词,可达路径用堆栈来保存,每次求取一组可达路径;
Step2:在迭代求取可达路径时,因已遍历过的路径不会保存,而只保留最优的一组,所以需标记记录已经迭代过的路径,这里用hash+list来设计标记。
建立个hash表,将beginWord、endWord、wordList中所有出现的单词建立一张映射表,key=word,value是一存放所有与该word相差一个字符的单词数组,如下:
{
'hit': ['hot'],
'lot': ['hot', 'dot', 'log'],
'dog': ['dot', 'log', 'cog'],
'hot': ['dot', 'lot', 'hit'],
'cog': ['dog', 'log'],
'dot': ['hot', 'dog', 'lot'],
'log': ['dog', 'lot', 'cog']
}
Step3:迭代过程如下图(反复往stack中push和pop的过程)
1) 将起始单词(hit)放入stack堆栈;
2) 从hash表中查找hit对应的value,顺序从该数组中选取,此处选取"hot"放入堆栈;
3) 循环调用2),依次将"dot","dog"...等放入堆栈 (见上图中最左处stack中的值)
4) 这里说明下"lot",lot对应的value数组为[‘hot’,‘dot’,‘log’],而hot,dot,log都已在stack中,即lot后无单词可往stack中放,该路径结束(弹出lot)
5) 继续按照4)的规则,依次弹出lot,放入cog,后又弹出cog、弹出log,放入cog,一条可达路径完成,记录下该路径;
6) 继续迭代,止到所有路径都遍历完毕(结束条件为stack中只剩下底部单词hit时)
5、代码示例 - Python
import time
import copy
class Solution:
def dist(self,word1,word2):
len1 = len(word1)
len2 = len(word2)
disNum = len1
if(len1 == len2):
for i in range(0,len1):
if (word1[i] == word2[i]):
disNum = disNum - 1
else:
disNum = disNum + 1
return disNum
def listToDict(self,begin,wd):
#build hash + link from wordlist
wd.append(begin) #add begin into dict
lenw = len(wd)
wdict = {}
for i in range (0,lenw):
for j in range(0,lenw):
dres = self.dist(wd[i],wd[j])
if(dres == 1):
if wdict.has_key(wd[i]):
wdict[wd[i]].append(wd[j])
else:
wdict[wd[i]] = [wd[j]]
return wdict
def ifLast(self,key,value,wdict):
valuel = wdict[key]
index = valuel.index(value)
if index == len(valuel)-1:
return 0
else:
return 1
def findLabbers(self,begin,end,wd):
wdict = self.listToDict(begin,wd)
max = len(wd) + 1
wstack = []
index = 0
wstack.append(begin)
top = 1 #top is the stack length
toppre = ""
res = [[]];
reslen = 0
#build stack
pre = ""
while wstack:
print "\n\n go while ---"
time.sleep(0.1)
'''
1. push to stack
2. loop to push until top == 1 or stack[top] = end
3. if top == 1
pop item and go to step 2
if stack[top] = end
save the res and pop item and go to step 2
if index + 1 > next.len
end the loop
'''
if wstack[top-1] == end:
#get one res
if reslen == 0:
res[reslen] = copy.deepcopy(wstack)
reslen = reslen + 1
else:
#find the min one
min = len(res[0])
if min > top:
while reslen > 1:
res.pop()
reslen = reslen - 1
res[reslen-1] = copy.deepcopy(wstack)
else:
if min == top:
res.append("")
res[reslen] = copy.deepcopy(wstack)
reslen = reslen + 1
else:
print "min<top: the result > exist res, not put into res list"
#loop to find another res
pre = wstack.pop()
top = top - 1
if wstack:
pre = wstack.pop()
top = top - 1 #when get res, pop twice
#if checked all the res, end the loop
if top == 1:
key = wstack[top-1]
if pre != "":
if self.ifLast(key,pre,wdict):
break #end the all loop
# build the stack
if wdict.has_key(wstack[top-1]):
valuel = wdict[wstack[top-1]]
#get the pre index, and loop from it
if pre == "" or pre not in valuel: #need remove duplicate here
index = 0;
else:
index = valuel.index(pre)
index = index + 1
#loop to get the item, which not in stack
while(index <= len(valuel)-1):
if (valuel[index] in wstack):
print "go 7 ---"
index = index + 1;
print "index, len(valuel)-1",index, len(valuel)-1
else:
break
#check whether have item to put into stack
if index <= len(valuel)-1:
#have item to put into stack
lenws = len(wstack)
#get the right item into stack
#the stack length shouldn't to be too long
if (lenws < max):
wstack.append(valuel[index])
else:
#if not the right item, pop to reloop
pre = wstack.pop()
top = top - 1
continue
else:
#no item to put into stack, pop to reloop
pre = wstack.pop()
top = top - 1
continue
top = top + 1
return res
if __name__ == "__main__":
wd = ["hot","dot","dog","lot","log","cog"]
begin = "hit"
end = "log"
st = Solution()
res = st.findLabbers(begin,end,wd)
print "\n\nget result ==============\n",res
---------------------------------------------------------------------------------------------------
本文链接:http://blog.youkuaiyun.com/karen0310/article/details/75013953
请尊重作者的劳动成果,转载请注明出处!