代码随想录 day 23 回溯

第七章 回溯算法part02

39. 组合总和

本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制
题目链接/文章讲解:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html
视频讲解:https://www.bilibili.com/video/BV1KT4y1M7HJ

40.组合总和II

本题开始涉及到一个问题了:去重。
注意题目中给我们 集合是有重复元素的,那么求出来的 组合有可能重复,但题目要求不能有重复组合。
题目链接/文章讲解:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html
视频讲解:https://www.bilibili.com/video/BV12V4y1V73A

131.分割回文串

本题较难,大家先看视频来理解 分割问题,明天还会有一道分割问题,先打打基础。
https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html
视频讲解:https://www.bilibili.com/video/BV1c54y1e7k6

39. 组合总和

题目链接

https://leetcode.cn/problems/combination-sum/description/

解题思路

startIndex 问题,题目说了这个数可以重复,由原来组合问题的 startIndex 传入i+1 变为 startIndex 传入 i 就是当前数 i 可以重复选取,i之前的数仍然不能用,否则会出现重复的组合,这和组合问题是一样的。
剪枝一定要在数组排序的情况下,当前sum+candidates[i]大于target了

code

class Solution {
 /**
    *
     * 本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?
     * 我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window),216.组合总和III (opens new window)。
     * 如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合
    **/

    /**
    * 回溯三部曲
     * 1.归函数参数
     * 2.递归终止条件
     * 3.单层搜索逻辑
    **/
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);//优化剪枝 对数组排序
        backtracking(candidates,target,0,0,path,res);
        return res;
    }

    public void backtracking(int[] candidates,int target,int startIndex,int sum){
        if(sum>target){
            return;
        }
        if(sum==target){
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = startIndex; i < candidates.length; i++) {
            //优化剪枝,在对数组排序的前提下,如果当前元素大于目标值,则后续元素肯定大于目标值,直接剪枝 target=8 [2,3,4]不满足  那么[2,3,5]更不满足了
            if(sum + candidates[i]> target) break;
            path.add(candidates[i]);
            sum+=candidates[i];
            backtracking(candidates,target,i,sum,path,res);//这里startIndex是i,表示可以重复使用
            path.remove(path.size()-1);
            sum-=candidates[i];
        }
    }
}

40.组合总和II

题目链接

https://leetcode.cn/problems/combination-sum-ii/description/

解题思路

这题相比上题,要考虑重复的问题,即出现相同元素,那么就要考虑到排序,排序后,如果后一个元素和前一个元素重复,那这个后一个元素就应该跳过,否则会出现重复的组合。

code

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path =new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            Arrays.sort(candidates);
            backtracking(candidates,target,0,0);
            return res;
    }

    public void backtracking(int[] candidates, int target,int sum,int startIndex){
        if(sum>target){
            return;
        }
        if(sum==target){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i=startIndex;i<candidates.length;i++){
            if(sum+candidates[i]>target){
                break;
            }
            if(i>startIndex && candidates[i]==candidates[i-1]){
                continue;
            }
            sum+=candidates[i];
            path.add(candidates[i]);
            backtracking(candidates,target,sum,i+1);
            sum-=candidates[i];
            path.remove(path.size()-1);
        }
    }
}

131.分割回文串

题目链接

https://leetcode.cn/problems/palindrome-partitioning/description/

解题思路

跟组合题目及其相似,只不过变为了分割元素,startIndex就是分割点, [startIndex,i] 就是分割的子串 s.substring(startIndex,i+1) substring方法是左闭有开, 每分割一次判断这个子串是不是回文,使用双指针判断
注意:最后一次收集结果的时候是进行i+1 所以终止条件是 startIndex==s.length() 而不是s.length()-1

code

class Solution {
    List<List<String>>  res=new ArrayList<>();
    List<String> path=new ArrayList<>();
    public List<List<String>> partition(String s) {
        backtracking(s,0);
        return res;
    }

    public void backtracking(String s,int startIndex){
        if(startIndex==s.length()){
            res.add(new ArrayList<>(path));
            return;
        }

        for(int i=startIndex;i<s.length();i++){
            String backStr = s.substring(startIndex,i+1);
            //判断是否是回文
            if(!isBackStr(backStr)){
                continue;
            }
            path.add(backStr);
            backtracking(s,i+1);
            path.remove(path.size()-1);
        }
    }
    public boolean isBackStr(String backStr){
        if(null==backStr || "".equals(backStr)){
            return false;
        }
        int left=0;
        int right=backStr.length()-1;
        while(left<=right){
            if(backStr.charAt(left)!=backStr.charAt(right)){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值