回溯法
废话不多说:回溯模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。回溯法就是暴力搜索,并不是什么高效的算法,最多再剪枝一下。
- 我们把回溯抽象树形结构看:横向遍历,加纵向遍历:
能够解决的问题:
组合问题: N个数里面按一定规则找出k个数的集合
77.组合
216.组合总和III
17.电话号码的字母组合
39.组合总和
40.组合总和II
分割问题: 一个字符串按一定规则有几种切割方式
子集问题 一个N个数的集合里有多少符合条件的子集
排列问题: N个数按一定规则全排列,有几种排列方式
棋盘问题
其他
实例:51 N皇后
n个皇后在棋盘NxN中,互不攻击(直线,横线,斜线只有一个皇后),求多少中摆放
class Solution {
int sum=0;
public int totalNQueens(int n) {
char[][] box=new char[n][n];
backtrack(n,0,box);
return sum;
}
//回溯模板
public void backtrack(int n,int row, char[][] box){
//终止条件,遍历到最后一行
if(row==n){
sum++;
return;
}
for(int col=0;col<n;col++){
if(isValid(row,col,n,box)){
box[row][col]=1;
backtrack(n,row+1,box);
box[row][col]=0;
}
}
}
//验证是否直线,竖线,斜线上出现过
public boolean isValid(int row,int col,int n,char[][] box){
for(int i=0;i<row;i++){
if(box[i][col]==1) return false;
}
for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
if(box[i][j]==1) return false;
}
for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
if(box[i][j]==1)return false;
}
return true;
}
}