回溯
带你深度解析回溯算法之 《回溯算法从入门到精通》
回溯算法模板
// 伪代码
List<Value> result;
void backtrack(路径, 选择列表) {
if (满足结束条件){
result.add(路径);
return;
}
for (选择 : 选择列表) {
做选择;
backtrack(路径, 选择路径);
撤销选择;
}
}
例1 : 全排列 (LeetCode. 46)
题目描述:给定一个 没有重复 数字的序列,返回其所有可能的全排列。
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;
}
void backtrack(int[] nums, LinkedList<Integer> track) {
// 定义出口
if (track.size() == nums.length) {
res.add(new LinkedList(track));
return;
}
for (int i = 0; i < nums.length; i++) {
// 剪枝 (排除不合法的选择)
if (track.contains(nums[i])) continue;
// 做选择
track.add(nums[i]);
// 进入下一层决策树
backtrack(nums, track);
// 撤销选择
track.removeLast();
}
}
}
例2 : N皇后 (LeetCode. 51)
题目描述:设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
class Solution {
List<List<String>> result = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
backtrack(new ArrayList<>(), 0, n);
return result;
}
public void backtrack(List<String> list, int row, int n) {
// 满足条件,加入到结果列表中,然后返回。
if(row == n) {
result.add(new ArrayList<>(list));
return;
}
for(int i = 0; i < n; i++) {
// 如果放置在该位置合法,则进行递归
if(isValid(i, list, row, n))
continue;
// 生成该行的字符串
list.add(generateString(i, n));
backtrack(list, row+1, n);
list.remove(list.size() - 1);
}
}
public boolean isValid(int pos, List<String> list, int row, int n) {
// 判断竖着有没有重合的
for(int i = 0; i < row; i++) {
if(list.get(i).charAt(pos) == 'Q') {
return false;
}
}
// 判断斜向有没有重合的
for(int i = row-1, j = pos-1; i >= 0 && j >= 0; i--, j--) {
if(list.get(i).charAt(j) == 'Q') {
return false;
}
}
for(int i = row-1, j = pos+1; i >= 0 && j < n; i--, j++) {
if(list.get(i).charAt(j) == 'Q') {
return false;
}
}
return true;
}
public String generateString(int pos, int n) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < pos; i++) {
sb.append(".");
}
sb.append("Q");
for(int i = pos+1; i < n; i++) {
sb.append(".");
}
return sb.toString();
}
}