2023-05-09 18:58阅读: 104评论: 0推荐: 0

【回溯算法】应用 I

回溯算法

力扣上典型的回溯算法相关题目如下:

应用

应用1:Leetcode.332

题目

332. 重新安排行程

分析

假设有 n 张机票,那么,就可以经过 n+1 个机场,因此,回溯过程的终止条件,即路径上的点的个数比机票数多 1

我们定义个递归函数:

def dfs(self, ticket_num: int, trips: dict[dict[int]], path: List[str]) -> bool:

利用后序遍历的思路,去判断从当前起点开始,能否经过所有的机场。

算法步骤:

  • 先对所有的机票按照字典序排序;

  • hashtrips 记录每一对起点到终点的数量;

  • 从起点开始,按照字典序回溯每一个目的机场最终能否经过所有的机场;

    • 如果能到达所有的机场,则该路径满足条件;

    • 如果不能到达所有的机场,则继续回溯。

代码实现

class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
trips = defaultdict(dict)
# 先对tickets按照字典序排序,因为python中的dict是有序字典
tickets.sort(key = lambda x: (x[0], x[1]))
for _from, _to in tickets:
if _from not in trips:
trips[_from] = defaultdict(int)
trips[_from][_to] += 1
path = ["JFK"]
self.dfs(len(tickets), trips, path)
return path
def dfs(self, ticket_num: int, trips: dict[dict[int]], path: List[str]) -> bool:
if len(path) == ticket_num + 1:
return True
start = path[-1]
# 优先遍历字典序靠前的目的机场,如果满足条件则加入路径中
for destination, count in trips[start].items():
if trips[start][destination] < 1:
continue
path.append(destination)
trips[start][destination] -= 1
if self.dfs(ticket_num, trips, path):
return True
path.pop()
trips[start][destination] += 1
return False

应用2:Leetcode.51

题目

51. N 皇后

分析

枚举每一个位置,回溯所有满足条件的位置,找到满足条件的路径,就记录下来。

算法步骤:

  • 从起点开始,从左上向右下,遍历所有的列;

  • 对于当前位置,检查是否可以放置皇后,同时满足如下规则:

    • 当前位置的正上方的列没有放置皇后;

    • 当前位置的左上方向没有放置皇后;

    • 当前位置的右上方向没有放置皇后。

  • 对于任意起点,递归的结束条件:从当前起点位置开始,所有的位置都已经处理完成,即遍历完棋盘上所有的行(0,,n1),row=n

  • 回溯完所有的位置后,记录满足条件的路径即可。

注:因为我们是从左上往右下的方向遍历的,所以,只需要判断已经经过的位置即可,不需要判断下方的位置。

代码实现

from typing import List
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
results = list()
path = [["."] * n for _ in range(n)]
visited = [["."] * n for _ in range(n)]
self.dfs(results=results, path=path, row=0, n=n, visited=visited)
return results
def dfs(self, results: List[List[str]], path: List[List[str]], row: int, n: int, visited: List[List[str]]):
if row == n:
results.append(list(["".join(candidate) for candidate in path]))
return
# 遍历所有的列,colum = 0 ... n-1
for column in range(n):
# 判断当前位置是否可以合法
if not self.is_valid(path, row, column):
continue
# 如果当前位置满足条件,继续回溯下一列
path[row][column] = "Q"
self.dfs(results, path, row + 1, n, visited)
path[row][column] = "."
return
def turn_right_top(self, start, end):
""" 朝右上方检查 """
i, j = start[0], start[1]
while i >= end[0] and j < end[1]:
yield i, j
i -= 1
j += 1
def turn_left_top(self, start, end):
""" 朝左上方检查 """
i, j = start[0], start[1]
while i >= end[0] and j >= end[1]:
yield i, j
i -= 1
j -= 1
def is_valid(self, path, row, column):
""" 是否可以在位置(row, column)放置皇后 """
# 检查正上方是否有皇后冲突
for x in range(len(path)):
if path[x][column] == "Q":
return False
# 检查右上方是否有皇后冲突
for x, y in self.turn_right_top((row - 1, column + 1), (0, len(path))):
if path[x][y] == "Q":
return False
# 检查左上方是否有皇后冲突
for x, y in self.turn_left_top((row - 1, column - 1), (0, 0)):
if path[x][y] == "Q":
return False
return True

应用3:Leetcode.37

题目

37. 解数独

分析

代码实现

class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
self.dfs(board)
return board
def dfs(self, board: List[List[str]]) -> bool:
# 遍历行
for i in range(len(board)):
# 遍历列
for j in range(len(board[0])):
# 只处理空格
if board[i][j] != ".":
continue
# 遍历1-9所有的数字
for num in range(1, 10):
# 如果当前数字不能填在当前位置,则跳过
if not self.is_valid(board, i, j, str(num)):
continue
board[i][j] = str(num)
if self.dfs(board):
return True
board[i][j] = "."
# 9个数都不满足,直接返回false
return False
return True
def is_valid(self, board, row, column, num) -> bool:
# 判断行
for i in range(9):
if board[i][column] == num:
return False
# 判断列
for j in range(9):
if board[row][j] == num:
return False
# 九宫格的起点
start_row = (row // 3) * 3
start_column = (column // 3) * 3
# 判断当前九宫格
for i in range(start_row, start_row + 3):
for j in range(start_column, start_column + 3):
if board[i][j] == num:
return False
return True

参考:

本文作者:LARRY1024

本文链接:https://www.cnblogs.com/larry1024/p/17385980.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   LARRY1024  阅读(104)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.