解决一个回溯问题,实际上就是一个决策树的遍历过程。
回溯可以解决的问题:
1,求全排列:全排列的值是:n个元素中取n个元素(全部元素)
2,求组合:n个元素,取m个元素(m<=n)的所有组合情况
3,求子集:n个元素的所有子集(所有的组合情况)
需要考虑3个问题:
1,路径:也就是已经可以做的选择。
2,路径列表:也就是你当前可以做的选择。
3,结束条件:也就是你到达决策树,无法再做选择的条件。
下面用一个“全排列”问题分析下:
回溯算法框架:
核心就是for循环里面的递归,在递归调用之前“做选择”,在递归调用之后“撤销选择”。
1,全排列问题
加入我们有三个数,那么排列组合 成一个数,没有重复的数字,例如:
123,132,213,231,312,321
整体代码:
package 备赛课.搜索;
public class 回溯 {
static int a[] = new int[10];
static int b [] =new int[10];
static int n = 3;
public static void main(String[] args) {
dfs(1);
}
static void dfs(int step){//当前在第几个位置
//1,满足的结束条件
if(step==n+1)//前n个数字已经放好
{
for(int i=1 ;i<=n;i++) System.out.print(a[i]+",");
return;
}
//每次都从1-n 逐步深度 开始分枝
for(int i = 1 ;i<=n;i++){
if(b[i]==0){//看这个数字是否用过
a[step]=i;//没用过,这个位置放放i;
b[i]=1;//表示i已经被用过,防止再用
dfs(step+1);//放好这个数字后,下一个数字,展开是一棵树
b[i]=0;//回溯,当满足一种全排列后,下一个尝试
}
}
return;
}
}
总结:
回溯算法就是一个多叉树遍历的问题,关键就是在前序遍历的位置做一些操作,其中核心框架还是下图:
例题2:括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
提示:
1 <= n <= 8
回溯方法:
class Solution {
public static List<String> generateParenthesis(int n) {
List<String > ans = new ArrayList<>();
int left=0 ,right=0;
back(ans,new StringBuilder(),left,right,n);
return ans;
}
static void back(List<String> ans, StringBuilder cur , int left, int right, int n ){
if(cur.length()==n*2){
ans.add(cur.toString());
return;
}
if(left<n){
cur.append("(");
back(ans,cur,left+1,right,n);
cur.deleteCharAt(cur.length()-1);//回溯
}
if(left>right){
cur.append(")");
back(ans,cur,left,right+1,n);
cur.deleteCharAt(cur.length()-1);//回溯
}
}
}
递归方法:
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if(n <= 0){
return res;
}
getParenthesis("",n,n);
return res;
}
private void getParenthesis(String str,int left, int right) {
if(left == 0 && right == 0 ){
res.add(str);
return;
}
if(left == right){
//剩余左右括号数相等,下一个只能用左括号
getParenthesis(str+"(",left-1,right);
}else if(left < right){
//剩余左括号小于右括号,下一个可以用左括号也可以用右括号
if(left > 0){
getParenthesis(str+"(",left-1,right);
}
getParenthesis(str+")",left,right-1);
}
}
}