回溯算法详解

解决一个回溯问题,实际上就是一个决策树的遍历过程。

回溯可以解决的问题:

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:括号生成

22. 括号生成 - 力扣(LeetCode)


数字 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);
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值