回溯算法(组合例)

最近几天力扣每日一题一直与回溯相关,因此想简单总结一下什么是回溯算法,如何解相关的回溯算法题,并给出一道例子。

一.什么是回溯算法

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

二.回溯算法的思想

其基本思想就是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

三.回溯算法的参数与过程

假设有一个迷宫,里面充满了很多的岔路口,我们需要探索从起点到达终点走出迷宫的路径,此时就需要进行一步一步的探索。

1.我们是在这个迷宫进行的探索,当我们走过一个岔路口时,下一次探索还是在这个迷宫,因此这就是我们的第一个参数:我们需要处理的数据(迷宫)。

2.当你选择了一条路时,这条路可能是我们需要的结果,因此我们需要保存我们走过的路,这就是我们的第二个参数:结果集

3.当你路过了一个岔路口到达下一个路口的时候,发现此路不通,是个死胡同,怎么办?是不是得原路返回。但我不知道原路啊?因为我只保存了上一个路口应该走哪条路,因此我们需要知道上一个路口的位置,此时就需要我们的第三个参数,保存上一条路位置,便于我们探索失败的时候返回。

4.接3,当你发现此路不通的时候,那这个路径还在结果集中吗?那这就肯定不是我们的结果了对吧,因此我们的结果集状态是不是得回退,把我们探索到的不同的那一条路从结果集中删掉,会退到上一个路口的状态。然后继续沿着路口继续探索。

5.成功条件,当我们走出迷宫就是成功了,此时退出迷宫,得到结果。

四.力扣例(39 组合总数)

题目:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取

分析:

找出所有的组合,可以一步一步的探索,即遍历数组,每次选取一个元素,满足条件加入结果集,否则回退。

因为数字可以被无限制重复被选取,因此我们在选取元素时,有两种选择,一是继续选择当前元素,一个是越过该元素,选取下一个

1.传入需要操作的数据 int[]candidates和我们的目标target。

2.传入我们的路径List<Integer>path,与所有的结果集List<List<integer>>res.

3.传入我们的目标sum,每进行一步探索,总和sum=sum-candidate[?]。

4.传入我们上一个路口的位置,int idx.

5.结束条件:a.我们的目标数被减完了,此时我们找到了一个结果,将结果加入到我们的结果集res中

                     b.因为我们沿着数组进行搜索,因此当我们搜索到最边缘时,此时不能够再继续下去,需要返回

 

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        List<Integer> path=new ArrayList<>();
        combine(candidates,target,path,res,0);
        return res;
    }
    private void combine(int can[],int sum,List<Integer>path,List<List<Integer>>res,int idx){
        
        if(sum==0){
            res.add(new ArrayList<>(path));
            return;
        }
        if(idx==can.length)return;
        //选取当前元素
        if((sum-can[idx])>=0){
            path.add(can[idx]);
            combine(can,sum-can[idx],path,res,idx);
            //移除最后一个元素
            path.remove(path.size()-1);
        }
        //不选当前元素
        combine(can,sum,path,res,idx+1);  
    }
}

此处不涉及剪枝操作,针对每一个回溯算法,剪枝策略大不相同,总的来说,就是将不可能的结果直接删掉,比如一个递增的序列,我现在需要组合得到7,那么经过一个操作之后选取了1,那么我还需要搜索6之后的数字吗?显然不可能,就直接将6之后的数字全部剪掉即可。

本人水平有限,错误之处还请希望指正!感谢! 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值