剑指 Offer 12. 矩阵中的路径(回溯,python注意二维数组浅拷贝问题)

https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。

回溯 + 深度优先遍历

思路:

  1. 从一个角落开始,遍历矩阵,选择开始格子。如果格子不等于第一个元素,则放弃,遍历下一个,直到找到等于第一个元素的格子。
  2. 对这个格子的前后左右进行判断,找到等于第二个元素且没有被遍历过的格子,作为下一步行进路线。格子是否被遍历过,用和矩阵维度相同的另一个矩阵进行记录。同理找到第三个格子。
  3. 当走到某个格子,发现其前后左右均无符合条件的格子,则进行回退,回到上一个节点重新选择,如果上一个节点周边没有另外一个元素符合要求,则进一步回退,直到找到某节点周围有能满足要求的另一个未被走过的节点,重复2过程

这是一个典型的回溯法的问题 参考leetcode官方讲解 https://leetcode-cn.com/problems/n-queens/solution/hui-su-suan-fa-xiang-jie-by-labuladong/
回溯法的核心就是递归调用的过程,在递归调用之前「做选择」,在递归调用之后「撤销选择」
其算法框架为

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

本题代码
时间复杂度,考虑搜索字符串长度为k,则每次搜索k个节点,每个节点搜索除过来节点的3个节点,则每次选定起始搜索点后,搜索时间复杂度3的k次幂。矩阵维度为m,n,则初始节点选择有mn种情况,时间复杂度O(mn*3^k)
空间复杂度使用额外矩阵记录节点是否被遍历O(m+n) 忽略递归深度

class Solution(object):
  def dfs(self, board, flag, row, col, word):
      if word == "":
          return True
      round_list = [(0, 1), (0, -1), (1, 0), (-1, 0)]
      for i in range(0, len(round_list)):
          if (row+round_list[i][0]) >= 0 and (row+round_list[i][0]) < len(board) and (col+round_list[i][1]) >= 0 and (col+round_list[i][1]) < len(board[0]) and not flag[row+round_list[i][0]][col+round_list[i][1]]:
              flag[row+round_list[i][0]][col+round_list[i][1]] = True
              if board[row+round_list[i][0]][col+round_list[i][1]] == word[0]:
                  if self.dfs(board, flag, row+round_list[i][0], col+round_list[i][1], word[1:]):
                      return True
              flag[row+round_list[i][0]][col+round_list[i][1]] = False
      return False

  def exist(self, board, word):
      """
      :type board: List[List[str]]
      :type word: str
      :rtype: bool
      """
      if len(board) == 0:
          if word == "":
              return True
          else:
              return False
      row = len(board)
      col = len(board[0])
      flag = [[False] * col for i in range(row)]   # 这里不能写成flag = [[False]*n]*m,因为这么定义,其实是将一个n列的数组浅拷贝m次,当更改flag[i][j] 元素时,所有行的第i列元素都会遭到更改
      for i in range(row):
          for j in range(col):
              if board[i][j] != word[0]:
                  continue
              flag[i][j] = True
              if self.dfs(board, flag, i, j, word[1:]):
                  return True
              flag[i][j] = False

      return False

剑指 Offer 12. 矩阵中的路径(回溯,python注意二维数组浅拷贝问题)_第1张图片

你可能感兴趣的:(leetcode,leetcode)