LeetCode 79. 单词搜索

题目

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

链接

79. 单词搜索 - 力扣(LeetCode)

作为一个初学者,我希望展示一下我的思考过程,以一个没见过这个题目的视角来思考这个问题

思路:

首先就是人工想一下怎么做, 遍历矩阵的每一个元素,作为起始点,判断这个点的四周有没有一个合法的方向, "ABCCD" 以A为起始点,然后看四个方向有没有B

如何转成代码,这个人工模拟的过程,其实就是一个dfs, 深度优先遍历,那怎么设计这个dfs呢,首先肯定是要一个x, y 作为一个当前节点, 然后得到这个

dfs(x, y) -> dfs(x + 1, y) dfs(x - 1, y) dfs(x, y + 1) dfs(x, y - 1)

然后就是如何有一个边界条件呢, 如果我们找到了这个单词,就是path 等于这个单词

len(path) == len(word) 或者如果四个方向都没有下一个字母,我们就return

这样一个大概框架就知道了(只是大概框架,后面很多要修改)

def dfs(x, y):
    if word[x][y] == word[len(path)]:
        path.append(word[x][y])
    else:
        return False
    
    if len(path) == len(word)
        return True
    flag = False
    
        return False
    for offset in offsets:
        i = x + offset[0]
        j = y + offset[1]
        if i < 0 of i >= m or j < 0 or j >= n:
            continue
        flag = flag or dfs(i, j)
    
    path.pop()
    return Flag

    

后面补充细节

1、 首先我们不能走回头路,因为同一个单元格我们无法重复使用

      策略: 添加visited

2、 如果flag == False 代表我们当前x,y 是行不通的

    策略: 我们以尝试过四个方向全是 False 后, 我们pop出去(恢复现场)

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        path = []
        n = len(board)
        m = len(board[0])
        def dfs(x, y, visited ):
            if board[x][y] == word[len(path)]:
                path.append(word[len(path)])
                visited[x][y] = True
            else:
                return False

            ## 边界条件
            if len(path) == len(word):
                return True
            flag = False

            for offset in offsets:
                i = x + offset[0]
                j = y + offset[1]
                if i < 0 or i >= n or j < 0 or j >= m or visited[i][j]:
                    continue
                flag = flag or dfs(i, j,visited)
            if flag == False:
                visited[x][y] = False
                path.pop()
            return flag
        
        for i in range(n):
            for j in range(m):
                path = []
                visited = [[False] * m for _ in range(n)]
                if dfs(i, j,visited):  return True
        return False

这样就可以通过了

优化(参考灵神代码)

79. 单词搜索 - 力扣(LeetCode)

1、 无需path 直接 用k 代表我们匹配到那个就ok

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n = len(board)
        m = len(board[0])
        def dfs(x, y, visited, k ):
            if board[x][y] == word[k]:
                visited[x][y] = True
            else:
                return False
            if k == len(word) - 1:
                return True
            flag = False

            for offset in offsets:
                i = x + offset[0]
                j = y + offset[1]
                if i < 0 or i >= n or j < 0 or j >= m or visited[i][j]:
                    continue
                flag = flag or dfs(i, j,visited, k + 1)

            visited[x][y] = False
            return flag
        
        for i in range(n):
            for j in range(m):
                path = []
                visited = [[False] * m for _ in range(n)]
                if dfs(i, j,visited, 0):  return True
        return False

2、 visited 可以优化

我们可以使用 board 代替visited 数组,如果访问过就把board[x][y]放置为 ' ’ 如果这个点走不通我们再把他恢复(因为肯定是匹配成功的所以恢复为word[k] 就可以, 这个样的好处一个是省空间

一个是我们不用再判断visited 是否为False ,因为匹配不成功在第一个就返回False了

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n = len(board)
        m = len(board[0])
        def dfs(x, y, k ):
            if board[x][y] == word[k]:
                board[x][y] = ''
            else:
                return False
            if k == len(word) - 1:
                return True
            flag = False

            for offset in offsets:
                i = x + offset[0]
                j = y + offset[1]
                if i < 0 or i >= n or j < 0 or j >= m:
                    continue
                flag = flag or dfs(i, j, k + 1)

            board[x][y] = word[k]
            return flag
        
        for i in range(n):
            for j in range(m):
                path = []
                if dfs(i, j, 0):  return True
        return False

3、 优化

我们无需等四个方向都判断完,如果有一个方向返回True 我们可以提前返回

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n = len(board)
        m = len(board[0])
        def dfs(x, y, k ):
            if board[x][y] == word[k]:
                board[x][y] = ''
            else:
                return False
            if k == len(word) - 1:
                return True
            flag = False

            for offset in offsets:
                i = x + offset[0]
                j = y + offset[1]
                if 0 <= i < n and 0 <= j < m and dfs(i, j, k + 1):
                    return True
            board[x][y] = word[k]
            return  False
        
        for i in range(n):
            for j in range(m):
                if dfs(i, j, 0):  return True
        return False

4、 代码稍微简化一下

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n, m = len(board), len(board[0])
        def dfs(x, y, k ):
            if board[x][y] != word[k]:
                return False

            if k == len(word) - 1:
                return True

            board[x][y] = ''
            for offset in offsets:
                i, j = x + offset[0], y + offset[1]
                if 0 <= i < n and 0 <= j < m and dfs(i, j, k + 1):
                    return True
            board[x][y] = word[k]
            return  False
        
        return any(dfs(i, j ,0) for i in range(n) for j in range(m))

5、 优化1 提前检索一下board 里有没有Word的字符

       优化2 假设word[0] 在board 里面有很多, word[-1] 很少,那么我们逆序word 更容易找到答案啊,逆序是不影响最后结果的

   

offsets = [[-1, 0], [1, 0], [0, 1], [0, -1]]
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        cnt = Counter(word)
        if not cnt >= Counter(word):
            return False
        if cnt[word[-1]] < cnt[word[0]]:
            word = word[::-1]
        n, m = len(board), len(board[0])
        def dfs(x, y, k ):
            if board[x][y] != word[k]:
                return False
            if k == len(word) - 1:
                return True

            board[x][y] = ''
            for offset in offsets:
                i, j = x + offset[0], y + offset[1]
                if 0 <= i < n and 0 <= j < m and dfs(i, j, k + 1):
                    return True
            board[x][y] = word[k]
            return  False
        
        return any(dfs(i, j ,0) for i in range(n) for j in range(m))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值