算法# 学习目标:优先搜索算法(三 )
学习内容:
优先搜索算法:包括深度优先搜索和广度优先搜索;深度优先搜索(DFS):在搜索到一个新节点时,立即对该新节点进行遍历;因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现;广度优先搜索(BFS):一层层进行遍历,需要用先入先出的队列进行遍历。
学习产出:
回溯法:优先搜索特殊情况,常用于需要记录状态的深度优先搜索。步骤有修改当前节点状态—递归子节点—回改当前节点状态;
1.按引用传状态
2.所有状态修改在递归后完成
回溯法修改一般有两种情况:一是修改最后一位;二是修改访问标记
回溯法
LeetCode 79 单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
修改访问标记,防止重复遍历,设置一个访问矩阵visited ,当已经访问过则设置为了True,回溯完后设置回来,当只有搜索成功时才返回True,如果backtracking无返回值,则返回False
。
代码(python)
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m,n = len(board),len(board[0])
visited = [[False for col in range(n)] for row in range(m)] #生成遍历标记矩阵
def backtracking(i, j, pos):
visited[i][j] = True #修改当前节点状态
if pos == len(word):
return True
#递归子节点
if i != m - 1 and board[i + 1][j] == word[pos] and not visited[i + 1][j]: #判断矩阵是否在边界或是已经遍历或词已经搜索出
if backtracking(i + 1, j, pos + 1):
return True
if i != 0 and board[i - 1][j] == word[pos] and not visited[i - 1][j]:
if backtracking(i - 1, j, pos + 1):
return True
if j != n - 1 and board[i][j + 1] == word[pos] and not visited[i][j + 1]:
if backtracking(i, j + 1, pos + 1):
return True
if j != 0 and board[i][j - 1] == word[pos] and not visited[i][j - 1]:
if backtracking(i, j - 1, pos + 1):
return True
visited[i][j] = False #修改回当前节点
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] == word[0]:
if (backtracking(i, j, 1)):
return True
return False
LeetCode 51 N 皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
类似于在矩阵中寻找字符串,也是通过修改状态矩阵来进行回溯,不同的是,对于每一行、列、斜建立访问数组,来记录是否存在皇后。分析发现,当满足条件的结果中每行或列有且仅有一个皇后。因此如果通过每一行来遍历插入皇后,则不需要对行建立访问数组。
代码(python)
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
ans = [] #输出矩阵
if n == 0 : return ans
board = [['.' for col in range(n)] for row in range(n)] #记录状态矩阵
colum = [False for row in range(n)] #列访问矩阵
ldiag = [False for row in range(2 * n )] #左斜访问矩阵
rdiag = [False for row in range(2 * n )] #右斜访问矩阵
def backtracking(ans,board,colum,ldiag,rdiag,row,n): #回溯函数
if row == n: #遍历结束
b = [] #调整输出结果
for i in range(n):
b.append(''.join(board[i]))
ans.append(b)
return
for i in range(n):
if colum[i] or ldiag[n-row+i-1] or rdiag[row+i+1]: #检测是否被访问
continue
board[row][i] = 'Q' #修改当前节点状态
colum[i] = ldiag[n-row+i-1] = rdiag[row+i+1] = True #修改当前访问节点状态
backtracking(ans,board,colum,ldiag,rdiag,row+1,n) #递归子节点
board[row][i] = '.' #回改当前节点状态
colum[i] = ldiag[n-row+i-1] = rdiag[row+i+1] = False #回改当前访问节点状态
backtracking(ans,board,colum,ldiag,rdiag,0,n)
return ans