[LeetCode解题报告] 127. 单词接龙

一、 题目

1. 题目描述

字典 wordList 中从单词 beginWord endWord转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk

  • 每一对相邻的单词只差一个字母。
  •  对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWord endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0

 

示例 1:

输入:beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出:5
解释:一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”, 返回它的长度 5。

示例 2:

输入:beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出:0
解释:endWord “cog” 不在字典中,所以无法进行转换。

 

提示:

  • 1 <= beginWord.length <= 10
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 5000
  • wordList[i].length == beginWord.length
  • beginWordendWordwordList[i] 由小写英文字母组成
  • beginWord != endWord
  • wordList 中的所有字符串 互不相同
Related Topics
  • 广度优先搜索
  • 哈希表
  • 字符串

  • 👍 1055
  • 👎 0
>

2. 原题链接

链接: 127. 单词接龙

二、 解题报告

1. 思路分析

本题状态需要在wordlist内转化,且每次只能改变一个单词,因此可以优化建图,在关系中插入虚拟节点。
例如:abc指向虚拟节点 b_c,a_b,ab_。

  1. 朴素BFS是可以的,状态就是变化后的单词,每次操作从单词里遍历所有位置选一个字母变成25个其他小写字母,所以状态转化单次操作数为n*26。当然不在wordlist里的剪掉。题目要求endword必须在单词列表里,可以先判。
    • 单词状态回溯建,实测有一定优化312ms
  2. 然后试了一下双向BFS,巨量优化,达到72ms,Python超过100%。
  3. 看了官方题解,可以优化建图:
    • 核心是在wordlist中对每个单词,变化每个字符为’',来作为虚拟节点,所有节点都连接虚拟节点,这样就可以建好连通路径,避免每个单词都进行n26的状态搜索。
    • 由于每两个点中间都有虚拟节点,因此最终路径要除以2。
    • 测试优化建图后朴素层先BFS速度不错136ms
  4. 然后试了下优化建图+双向BFS,92ms。
    这题由于wordlist的存在,每层状态剪枝很多,所以朴素做法效果不错。
    我琢磨最通用的做法应该还是优化建图+双层BFS,普遍性会高一些。

2. 复杂度分析

最坏时间复杂度O(n×c)

3. 代码实现

优化建图+双向bfs。92ms

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        abc = set(wordList)
        if endWord not in abc:
            return 0
        n = len(beginWord)
        graph = defaultdict(list)
        def add_egde(word):
            cs = list(word)
            
            for i in range(n):
                t = cs[i]
                cs[i] = '*'
                v_word = ''.join(cs)
                graph[v_word].append(word)
                graph[word].append(v_word)
                abc.add(v_word)    
                cs[i] = t
        for word in wordList:
            add_egde(word)
        add_egde(beginWord)

        v1 = {beginWord:0}
        v2 = {endWord:0}
        q1 = deque(v1)
        q2 = deque(v2)
        def bfs(q,v1,v2):
            for _ in range(len(q)):
                u = q.popleft()
                step = v1[u] 
                for v in graph[u]:
                    if v in v2:
                        return (step+1+v2[v])//2+1
                    if v not in v1:
                        v1[v] = step+1
                        q.append(v)
            return 0
        while q1 and q2:
            ret = bfs(q1,v1,v2) if len(q1) < len(q2) else bfs(q2,v2,v1)
            # print(v1,v2)
            if ret != 0:
                return ret
        return 0

优化建图+朴素层先法。136ms

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        abc = set(wordList)
        if endWord not in abc:
            return 0
        n = len(beginWord)
        graph = defaultdict(list)
        def add_egde(word):
            cs = list(word)
            
            for i in range(n):
                t = cs[i]
                cs[i] = '*'
                v_word = ''.join(cs)
                graph[v_word].append(word)
                graph[word].append(v_word)
                abc.add(v_word)    
                cs[i] = t
        for word in wordList:
            add_egde(word)
        add_egde(beginWord)

        visited = {beginWord}
        step = 0
        q = deque(visited)
        while q:
            new_q = deque()
            step += 1
            while q:
                u = q.popleft()
                for v in graph[u]:
                    if v == endWord:
                        return step//2+1
                    if v not in visited:
                        visited.add(v)
                        new_q.append(v)
            q =new_q

        return 0
            

双向BFS。72ms

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        abc = set(wordList)
        if endWord not in abc:
            return 0
        n = len(beginWord)
       
        v1 = {beginWord:1}
        v2 = {endWord:0}
        q1 = deque(v1)
        q2 = deque(v2)
        def bfs(q,v1,v2):
            for _ in range(len(q)):
                x = q.popleft()
                step = v1[x] + 1
                cur = list(x)
                for i in range(n) :
                    t = cur[i]
                    for c in 'abcdefghijklmnopqrstuvwxyz':                        
                        cur[i] = c
                        nxt = ''.join(cur)                  
                        if nxt in v2:
                            return step+v2[nxt]      
                        if nxt in abc and nxt not in v1:                            
                            v1[nxt] = step
                            q.append(nxt)
                    cur[i] = t
            return -1
        while q1 and q2:
            ret = bfs(q1,v1,v2) if len(q1) < len(q2) else bfs(q2,v2,v1)
            # print(v1,v2)
            if ret != -1:
                return ret
        return 0

            

朴素层先法BFS。312ms

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        abc = set(wordList)
        if endWord not in abc:
            return 0
        n = len(beginWord)
        visited = {beginWord}
        q =deque(visited)
        step = 1
        while q:
            # print(q,step)
            new_q = deque()
            step += 1
            while q:
                x = list(q.popleft())
                # nxt = x[:]
                for i in range(n) :
                    t = x[i]
                    for c in 'abcdefghijklmnopqrstuvwxyz':                        
                        x[i] = c
                        nxt = ''.join(x)                  
                        if nxt == endWord:
                            return step      
                        if nxt in abc and nxt not in visited:
                            
                            visited.add(nxt)
                            new_q.append(nxt)
                    x[i] = t
                        
            q = new_q
        return  0            

三、 本题小结

  1. 优化见图的思路想法需要多做题多思考。
  2. 继续练习双向BFS。

四、 参考链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值