【LeetCode】面试题12. 矩阵中的路径

题目:

思路:

因为可以从矩阵中任意一格开始,所以拿到题之后的思路为: 遍历整个矩阵,尝试把每个点当作起始点去搜索路径,直到找到或者遍历完。考虑到有点暴力,感觉不是最优方法,所以一直在思考更优的方法(也被它动态规划的标签误导了),陷入了瓶颈,没有把之前的暴力思路抽象到深度优先搜索的方法论。
另外一直在把思路复杂化,考虑记录每次进入某个节点的方向,避免形成循环。而参考了代码中的思路之后,将当前值置为"/",避免了循环。从而能够抽象到特别简单的DFS中,只需要考虑边界就可以了,避免了复杂的条件判断。
也想到了另一个方法: 对整个矩阵遍历K轮,第k轮遍历找到矩阵中等于目标字符串位置k的字符,查看该位置的上下左右,是否已经组成了前k-1个目标字符串,需要注意的点有: 避免循环,到达某个点的路径可能有多条,都需要记录下来。

代码:

Python

# Solution1 84/87超时
# [["A","B","C","E"],["S","F","E","S"],["A","D","E","E"]] "ABCESEEEFS"
# [["a"]] "a"
# [["a", "a"], ["a", "a"]]  "aaaaa"
import copy
class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        x = len(board)
        y = len(board[0])
        # 构造now记录每个位置的当前路径[[[set(), set()], []], [[], []]]
        # 每个点通过一个list记录,有几条路径list中就有几个元素,每个元素是set,保证路径不重复
        # 构造过程也是第一个目标字符的遍历过程
        now = list()
        for i in range(x):
            tmp = list()
            for j in range(y):
                if board[i][j] == word[0]:  # 目标字符串长度为1的情况
                    if len(word) == 1:
                        return True
                    # 保证是list(set(tuple))结构
                    a = set()
                    a.add((i, j))
                    tt = list()
                    tt.append(a)
                    tmp.append(tt)
                else:
                    tmp.append(list())
            now.append(tmp)
        # 遍历剩余目标字符
        for c in range(1, len(word)):
            # 因为会修改now,避免修改后的now被用于当前轮次
            pre = copy.deepcopy(now)
            this_char = word[c]
            for i in range(x):
                for j in range(y):
                    now[i][j] = list()
                    # 遍历整个矩阵,对等于当前目标字符的位置。查看它的上下左右,是否存在长度为c的前缀路径,把它们全部找出来
                    if board[i][j] == this_char:
                        pre_list = list()
                        if i - 1 >= 0 and len(pre[i-1][j]) > 0:
                            pre_list.extend(pre[i-1][j])
                        if j - 1 >= 0  and len(pre[i][j-1]) > 0:
                            pre_list.extend(pre[i][j-1])
                        if i + 1 < x and len(pre[i+1][j]) > 0:
                            pre_list.extend(pre[i+1][j])
                        if j + 1 < y and len(pre[i][j+1]) > 0:
                            pre_list.extend(pre[i][j+1])
                        # 对每一个前缀路径,添加当前节点
                        # 如果重复则整个前缀路径失效,判断是否找到
                        for e in pre_list:
                            ee = copy.deepcopy(e)  # 这里不copy会修改pre的数据??
                            ee.add((i, j))
                            if len(ee) == len(word):
                                return True
                            if len(ee) == (c+1):
                                now[i][j].append(ee)
        return False
# Solution2
class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        def dfs(i, j, k):
            # 边界条件,是否进入该节点
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
            if k == len(word) - 1: return True
            tmp, board[i][j] = board[i][j], '/'  # 避免循环,深度遍历时整条路径都被置为"/"
            # 递归遍历
            res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)
            board[i][j] = tmp
            return res
        # 把每个节点作为起始点开始遍历
        for i in range(len(board)):
            for j in range(len(board[0])):
                if dfs(i, j, 0): return True
        return False

相关问题

原文地址:https://www.cnblogs.com/cling-cling/p/12956930.html