[LeetCode]127. Word Ladder 深入浅出讲解和代码示例


1、汇总概要


本题解题思路中用到了哈希、堆栈的知识点。

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:

  1. Only one letter can be changed at a time.
  2. 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.csdn.net/karen0310/article/details/75013953
请尊重作者的劳动成果,转载请注明出处!
---------------------------------------------------------------------------------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值