本文主要是介绍代码随想录算法训练营第三十天丨332. 重新安排行程、51. N 皇后、37. 解数独,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
332. 重新安排行程
自己写的话暴力全排列了,没用用到图结构来简化路径搜索。感觉理论上能解决,提交后超时。
记录一下深度优先搜索的图算法:
from collections import defaultdict
class Solution:def findItinerary(self, tickets: List[List[str]]) -> List[str]:res = []graph = defaultdict(list)for src,dst in sorted(tickets, reverse=True):graph[src].append(dst)def backtrack(airport):while graph[airport]:next_airport = graph[airport].pop()backtrack(next_airport)res.append(airport)backtrack('JFK')return res[::-1]
51. N 皇后
大一第一学期,python程序设计课的课程作业... 都已经9年了吗..为什么我还是这么菜!
class Solution:def solveNQueens(self, n: int) -> List[List[str]]:def backtrack(row):if row == n:board = build_board()result.append(board)returnfor col in range(n):if col in cols or (row + col) in diag1 or (row - col) in diag2:continuecols.add(col)diag1.add(row + col)diag2.add(row - col)queens[row] = colbacktrack(row + 1)cols.remove(col)diag1.remove(row + col)diag2.remove(row - col)def build_board():board = []for i in range(n):row = ['.'] * nrow[queens[i]] = 'Q'board.append(''.join(row))return boardresult = []queens = [-1] * n # 记录每行皇后的列位置cols = set() # 记录已经放置皇后的列diag1 = set() # 记录主对角线上的位置(r + c)diag2 = set() # 记录副对角线上的位置(r - c)backtrack(0)return result
37. 解数独
同样也是期末课程设计的选题之一...
class Solution:def solveSudoku(self, board: List[List[str]]) -> None:"""Do not return anything, modify board in-place instead."""rows = [set(range(1, 10)) for _ in range(9)] # 每行可用数字cols = [set(range(1, 10)) for _ in range(9)] # 每列可用数字boxes = [set(range(1, 10)) for _ in range(9)] # 每个宫格可用数字empty = [] # 记录空格位置# 初始化for i in range(9):for j in range(9):if board[i][j] != '.':val = int(board[i][j])rows[i].remove(val)cols[j].remove(val)boxes[(i // 3) * 3 + j // 3].remove(val)else:empty.append((i, j))def backtrack(iter=0):if iter == len(empty): # 所有空格已填完return Truei, j = empty[iter]b = (i // 3) * 3 + j // 3for val in rows[i] & cols[j] & boxes[b]:rows[i].remove(val)cols[j].remove(val)boxes[b].remove(val)board[i][j] = str(val)if backtrack(iter + 1):return Truerows[i].add(val)cols[j].add(val)boxes[b].add(val)board[i][j] = '.'return Falsebacktrack()
总结:
回溯算法的本质
回溯算法本质上是一种通过递归来实现深度优先搜索(DFS)的算法。它试图在每一步做出选择,然后继续向前探索,如果发现当前选择并不是一个正确的解或者是一个最优解,它会撤销这个选择(也就是所谓的“回溯”),然后尝试其他的选项。
应用场景
回溯算法可以应用于多种问题,包括但不限于:
- 组合问题:从N个数中选出k个数的所有可能组合。
- 排列问题:N个数的所有排列方式。
- 切割问题:如将字符串切割成回文串的所有可能方式。
- 子集问题:求一个集合的所有子集。
- 棋盘问题:如N皇后问题,解数独等。
解题模板
回溯算法有一个通用的解题模板,基本上包括以下几个步骤:
- 路径:已经做出的选择。
- 选择列表:当前可以做的选择。
- 结束条件:到达决策树底层,无法再做选择的条件。
代码模板大致如下:
void backtrack(路径, 选择列表) {if (满足结束条件) {存放结果;return;}for (选择 : 选择列表) {做选择;backtrack(路径, 选择列表);撤销选择;}
}
剪枝优化
在实际应用中,为了提高回溯算法的效率,常常需要进行剪枝操作,即在递归过程中提前排除那些明显不会得到正确解的路径,从而减少不必要的计算。
这篇关于代码随想录算法训练营第三十天丨332. 重新安排行程、51. N 皇后、37. 解数独的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!