回溯算法详解
解决一个回溯问题,实际上就是一个决策树的遍历过程。
两种决策树的遍历:
如上,参数t为当前在决策树的层数。
子集树:针对在解向量中选择满足条件的子集),如背包问题;
排列树:针对解向量的排序问题,如全排列、八皇后问题。
全排列问题
问题描述
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
解题思想
很明显该问题是一个解向量的排序问题,可以直接套用遍历排列树的模板:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
for (int num : nums) {
path.add(num);
}
int n = nums.length;
backtrack(n, path, res, 0);
return res;
}
public void backtrack(int n, List<Integer> path, List<List<Integer>> res, int t) {
if (t >= n) {//到了最后一层
res.add(new ArrayList<Integer>(path));
}
for (int i = t; i < n; i++) {
Collections.swap(path, t, i);//swap(List list,int i,int j):交换集合中指定元素索引的位置
backtrack(n, path, res, t + 1);
Collections.swap(path, t, i);
}
}
}
时间复杂度:O(n!)
空间复杂度:O(n)
N皇后问题
问题描述
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
注:
1 <= n <= 9
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
解题思路
因为n*n的棋盘上要放n个皇后,又因为皇后不能在同一行同一列和同一对角线,所以必定每一行都要放一个皇后,那么假设皇后在列上的坐标为xi,xi表示第i行的皇后在第xi列,xi∈(0,…,n-1),由此,可以看出该问题是一个对解向量的排列问题,可套用排列树的模板。其实该问题也可用子集树求解。
与全排列问题不同的是,该题需要考虑剪枝问题,若不满足放置规则则剪枝:
针对第i行的皇后和第j行的皇后:
1)俩皇后不在同一列:xi != xj;
2)俩皇后不在同一对角线:| i-j | != | xi-xj|
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<List<String>>();
int row[] = new int[n];//用row存储皇后在列上的排列顺序
backtrack(res,row,n,0);
return res;
}
public void backtrack(List<List<String>> res,int[] row,int n,int t){//遍历子集树
if(t >= n)
output(res,row,n);
else{
for (int i = 0; i < n; i++){
row[t] = i;
if(legal(row,t))
backtrack(res,row,n, t+1);
}
}
}
public boolean legal(int[] row,int t){ //判断是否为有效的坐标
for(int i=0;i<t;i++){
if(Math.abs(i-t)==Math.abs(row[i]-row[t]) || row[i]==row[t])
return false;
}
return true;
}
public void output(List<List<String>> res,int[] row,int n){ //打印结果
List<String> temp_res = new ArrayList<String>();
for(int i=0;i<n;i++){
String line = "";
for(int j=0;j<n;j++){
if(j == row[i])
line = line + 'Q';
else
line = line + '.';
}
temp_res.add(line);
}
res.add(temp_res);
}
}
时间复杂度:O(2^n)
空间复杂度:O(n)