Appearance
回溯算法
解决一个回溯问题,实际上就是一个决策树的遍历过程。
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」
一、全排列问题
只要从根遍历这棵树,记录路径上的数字,其实就是所有的全排列。我们不妨把这棵树称为回溯算法的「决策树」。
我们定义的 backtrack
函数其实就像一个指针,在这棵树上游走,同时要正确维护每个节点的属性,每当走到树的底层,其「路径」就是一个全排列。
如何遍历一棵树?各种搜索问题其实都是树的遍历问题,而多叉树的遍历框架就是这样:
void traverse(TreeNode root) {
for (TreeNode child : root.childern)
// 前序遍历需要的操作
traverse(child);
// 后序遍历需要的操作
}
前序遍历的代码在进入某一个节点之前的那个时间点执行,后序遍历代码在离开某个节点之后的那个时间点执行。
class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
LinkedList<Integer> track = new LinkedList<>();
backtrack(nums,track);
return res;
}
public void backtrack(int[] nums,LinkedList<Integer> track){
if(track.size()==nums.length){
res.add(new LinkedList(track));
return;
}
for(int num:nums){
if(!track.contains(num)){
track.add(num);
backtrack(nums,track);
track.removeLast();
}
}
}
}
这个算法解决全排列不是很高效,这也是回溯算法的一个特点,不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高。
二、N 皇后问题
class Solution {
List<List<String>> res = new ArrayList<>();
// 输入棋盘的边长n,返回所有合法的放置
public List<List<String>> solveNQueens(int n) {
// "." 表示空,"Q"表示皇后,初始化棋盘
char[][] board = new char[n][n];
for (char[] c : board) {
Arrays.fill(c, '.');
}
backtrack(board, 0);
return res;
}
public void backtrack(char[][] board, int row) {
// 每一行都成功放置了皇后,记录结果
if (row == board.length) {
res.add(charToList(board));
return;
}
int n = board[row].length;
// 在当前行的每一列都可能放置皇后
for (int col = 0; col < n; col++) {
// 排除可以相互攻击的格子
if (!isValid(board, row, col)) {
continue;
}
// 做选择
board[row][col] = 'Q';
// 进入下一行放皇后
backtrack(board, row + 1);
// 撤销选择
board[row][col] = '.';
}
}
/* 判断是否可以在 board[row][col] 放置皇后 */
public boolean isValid(char[][] board, int row, int col) {
int n = board.length;
// 检查列是否有皇后冲突
for (int i = 0; i < n; i++) {
if (board[i][col] == 'Q') {
return false;
}
}
// 检查右上方是否有皇后冲突
for (int i = row - 1, j = col + 1; i >=0 && j < n; i--, j++) {
if (board[i][j] == 'Q') {
return false;
}
}
// 检查左上方是否有皇后冲突
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') {
return false;
}
}
return true;
}
public List charToList(char[][] board) {
List<String> list = new ArrayList<>();
for (char[] c : board) {
list.add(String.copyValueOf(c));
}
return list;
}
}