算法编程中的Word 四兄弟 Word Break , Word Ladder, Word Search, Word Pattern

Word 四兄弟 Word Break , Word Ladder, Word Search, Word Pattern, 太容易出现了,针对性分析下。

 

 

829 · 字模式 II
算法
困难
通过率47%
 
描述

给定一个pattern和一个字符串str,查找str是否遵循相同的模式。
这里遵循的意思是一个完整的匹配,在一个字母的模式和一个非空的单词str之间有一个双向连接的模式对应。(如果a对应s,那么b不对应s。例如,给定的模式= "ab", str = "ss",返回false)。

您可以假设模式str只包含小写字母

样例

样例1

输入:
pattern = "abab"
str = "redblueredblue"
输出: true
说明: "a"->"red","b"->"blue"

样例2

输入:
pattern = "aaaa"
str = "asdasdasdasd"
输出: true
说明: "a"->"asd"

样例3

输入:
pattern = "aabb"
str = "xyzabcxzyabc"
输出: false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution:
    """
    @param pattern: a string,denote pattern string
    @param str: a string, denote matching string
    @return: a boolean
    """
    def wordPatternMatch(self, pattern, string):
        return self.is_match(pattern, string, {}, {})
 
    def is_match(self, pattern, string, mapping, mapping2):
        if not pattern:
            return not string
             
        char = pattern[0]
        if char in mapping:
            word = mapping[char]
            if not string.startswith(word):
                return False
            return self.is_match(pattern[1:], string[len(word):], mapping, mapping2)
             
        for i in range(len(string)):
            word = string[:i + 1]
            if word in mapping2:
                continue
             
            mapping2[word] = char
            mapping[char] = word
             
            if self.is_match(pattern[1:], string[i + 1:], mapping, mapping2):
                return True
             
            del mapping[char]
            del mapping2[word]
                         
        return False
        

  

要点:

1
2
if word in mapping2:
      continue<br>理解下:
这里我们为什么需要一个额外的 mapping2 呢? 
		  
			一个好的测试用例是:
			pattern:    "bdpbibletwuwbvh"
			str:        "aaaaaaaaaaaaaaa"
			
		 这里第一次执行时, mapping中匹配了 b -> a 
		 递归进去以后第二次执行时,d 没有在 mapping 中,所以跳过了map的匹配检测,
		 所以进入循环体, 这时第二个word 又是 a, 按道理 a 应该被 b 匹配并且之前应该在mapping.containsKey的检查中跳出, 但现在并没有跳出,而是试图绑匹配给另一个pattern的字母 d, 
		 很明显 b != d 重复绑定不是正确结果, 所以需要continue掉这次尝试。
		 
		 当然, 我们可以直接用map.containsValue(d), 因为之前map检查中己经跳出了如果己经绑定过,现在又出现了,就意味着重复绑定, 或者说不是匹配的。 
                之所以单独开了这个mapping2 因为map.containsValue需要额外的O(n)时间, 实际上就是以空间换时间或时间换空间的选择。

		 

 

单词接龙 II · Word Ladder II

给出两个单词(startend)和一个字典,找出所有从startend的最短转换序列。

变换规则如下:

  1. 每次只能改变一个字母。
  2. 变换过程中的中间单词必须在字典中出现。
  1. 所有单词具有相同的长度。
  2. 所有单词都只包含小写字母。
  3. 题目确保存在合法的路径。

样例

样例 1:

输入:

start = "a"
end = "c"
dict =["a","b","c"]

输出:

[["a","c"]]

解释:

"a"->"c"

样例 2:

输入:

start ="hit"
end = "cog"
dict =["hot","dot","dog","lot","log"]

输出:

[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]

解释:

1."hit"->"hot"->"dot"->"dog"->"cog"
2."hit"->"hot"->"lot"->"log"->"cog"

dijstra算法会出现mem超出限制!!!
先用bfs找到target距离,再用dfs寻找路径,会超时。。。你妹哦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from typing import (
    List,
    Set,
)
import heapq
 
 
class Solution:
    """
    @param start: a string
    @param end: a string
    @param dict: a set of string
    @return: a list of lists of string
             we will sort your return value in output
    """
    def find_ladders(self, start: str, end: str, dict: Set[str]) -> List[List[str]]:
        # write your code here
        self.next_word_dict = {}
        distance = self.bfs(start, end, dict)
        self.ans = []
        print("distance", distance)
         
        self.dfs(start, end, dict, distance, layer=0, path=[start])
        return self.ans
 
    def bfs(self, start, end, mapping):       
        mapping.add(end)
 
        q = [start]
        seen = {start}
        distance = 0
 
        while q:
            # print("q=>", q)           
            q2 = []
            distance += 1
            for virtex in q:
                for word in self.get_neibors(virtex, mapping):               
                    if word not in seen:
                        q2.append(word)                   
                        seen.add(word)
 
                    if word == end:
                        return distance
            #print("q", q)
            #print("q2", q2)
            q = q2
                     
        return distance
     
    def get_neibors(self, word, words_set):
        if word in self.next_word_dict:
            return self.next_word_dict[word]
 
        words = []
        for i in range(len(word)):
            left, right = word[:i], word[i + 1:]
            for char in 'abcdefghijklmnopqrstuvwxyz':
                if word[i] == char:
                    continue
                  
                word2 = left + char + right             
                if word2 in words_set:                  
                    words.append(word2)
         
        self.next_word_dict[word] = words
        return words
 
    def dfs(self, start, end, mapping, distance, layer, path):
        if layer == distance:
            if end == start:
                self.ans.append(list(path))
            return
         
        for word in self.get_neibors(start, mapping):  
            # if word not in path: 
            if len(path) < 2 or word != path[-2]:             
                path.append(word)
                # print("paht:", path)
                self.dfs(word, end, mapping, distance, layer+1, path)
                path.pop()  
优化下,使用distance记录bfs中的节点到start的距离,然后在dfs遍历中,看是否满足距离,这样去卡dfs的节点:(使用BFS的原因为了预处理出最短路径。如果只使用DFS会超时因为会遍历所有的可能。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from typing import (
    List,
    Set,
)
import heapq
 
 
class Solution:
    """
    @param start: a string
    @param end: a string
    @param dict: a set of string
    @return: a list of lists of string
             we will sort your return value in output
    """
    def find_ladders(self, start: str, end: str, dict: Set[str]) -> List[List[str]]:
        # write your code here
        self.next_word_dict = {}
        distance = self.bfs(start, end, dict)
        self.ans = []
        # print("distance", distance)
         
        self.dfs(start, end, dict, distance, layer=0, path=[start])
        return self.ans
 
    def bfs(self, start, end, mapping):       
        mapping.add(end)
 
        q = [start]
        seen = {start}
        distance = {}
        layer = 0
 
        while q:      
            q2 = []
            layer += 1
            for virtex in q:
                for word in self.get_neibors(virtex, mapping):               
                    if word not in distance:
                        q2.append(word)                   
                        distance[word] = layer
 
                    if word == end:
                        return distance
 
            q = q2
                     
        return distance
     
    def get_neibors(self, word, words_set):
        if word in self.next_word_dict:
            return self.next_word_dict[word]
 
        words = []
        for i in range(len(word)):
            left, right = word[:i], word[i + 1:]
            for char in 'abcdefghijklmnopqrstuvwxyz':
                if word[i] == char:
                    continue
                  
                word2 = left + char + right             
                if word2 in words_set:                  
                    words.append(word2)
         
        self.next_word_dict[word] = words
        return words
 
    def dfs(self, start, end, mapping, distance, layer, path):
        if end == start:
            self.ans.append(list(path))
            return
         
        for word in self.get_neibors(start, mapping):  
            if word in distance and distance[word] == layer+1:
                path.append(word)
                self.dfs(word, end, mapping, distance, layer+1, path)
                path.pop()

  

单词搜索 II · Word Search II

描述

给出一个由小写字母组成的矩阵和一个字典。找出所有同时在字典和矩阵中出现的单词。一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动。一个字母在一个单词中只能被使用一次。且字典中不存在重复单词

样例

样例 1:

输入:["doaf","agai","dcan"]["dog","dad","dgdg","can","again"]
输出:["again","can","dad","dog"]
解释:
  d o a f
  a g a i
  d c a n
矩阵中查找,返回 ["again","can","dad","dog"]

样例 2:

输入:["a"],["b"]
输出:[]
解释:
 a
矩阵中查找,返回 []

挑战

使用单词查找树来实现你的算法

 

直接暴力做要悲剧,todo,trie写下。。。

 



posted @   bonelee  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2021-06-09 后渗透就是获取服务器、shell权限、AD权限
2021-06-09 网络安全top国际会议
2017-06-09 时间序列数据库压缩
点击右上角即可分享
微信分享提示