算法练习 Day27 | leetcode 39. 组合总和,40.组合总和II,131.分割回文串

一、算法题

39. 组合总和

题目链接

class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backtracking(candidates, target, 0,0);
        return result;
    }

    public void backtracking(int[] candidates,int target,int startindex,int sum){
        //回溯结束条件
        if(sum>target){
            return;
        }
        if(sum==target){
            result.add(new ArrayList<>(path));
            return;
        }
        for(int i=startindex;i<candidates.length;i++){
            path.add(candidates[i]);
            sum+=candidates[i];
            backtracking(candidates, target, i, sum);
            path.removeLast();
            sum-=candidates[i];
        }
    }
}

40.组合总和II

题目链接

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new LinkedList<>();
    boolean[] used;

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        used=new boolean[candidates.length];
        Arrays.fill(used, false);
        //排序
        Arrays.sort(candidates);
        backtracking(candidates, target, 0, 0);
        return result;
    }

    public void backtracking(int[] candidates, int target, int startindex, int sum) {
        // 回溯结束条件
        if (sum == target) {
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = startindex; i < candidates.length; i++) {
            if(sum+candidates[i]>target){
                break;
            }
            //去重
            if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false){
                continue;
            }
            path.add(candidates[i]);
            sum += candidates[i];
            used[i]=true;
            backtracking(candidates, target, i + 1, sum);
            path.removeLast();
            sum -= candidates[i];
            used[i]=false;
        }
    }
}
  • 本题的难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合
    • 元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。
      • 比如candidates = [10,1,2,7,6,1,5],target=4,可以出现[1,1,2],但是不能[1,1,2],[1,2,1]同时出现,这相当于重复了
      • 只能同一个树枝上数值重复,因为使用的数字虽然数值一样但不是同一个
      • 同一层上不能重复
    • 我们要去重的是同一树层上的“使用过”
    • 同一树枝上的都是一个组合里的元素,不用去重
  • 树层去重的话,需要对数组排序
  • used数组
    • used数组与candidate数组一样大,对应每个位置,表示该数字是否被使用
    • 如果 i>0,且candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1],此时continue进入下一次循环
    • 这样做是因为前后数值相同,但是前一个数字没被使用,说明同一层的前一个树枝肯定使用了i-1这个数值,因为i从0开始,所以i=0时一定会先取第一个数,那么他对应的used[i]=true
    • 因为前一个树枝取的数字与这个数值的数字相同,所以它肯定包含所有可能,同时会把该树枝的所有可能包含在内,这样如果把该树枝的回溯结果保存起来的话就会出现重复问题
      • 比如
      • target=3,第一层第二个树枝有[1],[1,2]这个结果;而第一层第一个树枝会有[1],[1,1],[1,2],[1,1,2];则前一个树枝已经包含了第二个树枝满足条件的组合

131.分割回文串

题目链接

class Solution {
    List<List<String>> result=new ArrayList<>();
    List<String> path=new LinkedList<>();
    public List<List<String>> partition(String s) {
        backtracking(s, 0);
        return result;
    }
    public void backtracking(String s,int startindex){
        if(startindex>=s.length()){
            result.add(new ArrayList<>(path));
            return;
        }
        for(int i=startindex;i<s.length();i++){
            if(huiwen(s, startindex, i)){
                //取到end的前一个
                //startindex用于去重,控制取得数组里的每个数作为开头
                //i是在startindex取得开头后,遍历以那个数为开头的数组中的每一个数
                //比如[1,2,3],startindex=2,i遍历[2,3]
                String str=s.substring(startindex,i+1);
                path.add(str);
            }
            else{
                //不是回文串
                continue;
            }
            backtracking(s,i+1);
            path.removeLast();
        }

    }
    public boolean huiwen(String s,int start,int end){
        for(int i=start,j=end;i<j;i++,j--){
            if(s.charAt(i)!=s.charAt(j)){
                //不是回文串
                return false;
            }
        }
        return true;
    }
}
  • if(startindex>=s.length()){
                result.add(new ArrayList<>(path));
                return;
            }
    • 起始位置startindex=s.length的时候,说明已经遍历完了
      • 比如s="abc",s.length=3,起始位置startindex从0开始,到2结束
      • 当起始位置startindex=3时,说明已经遍历完三个字母了
  • s.substring(startindex,i+1)
    • 取到end的前一个
    • startindex用于去重,控制取得数组里的每个数作为开头
    • i是在startindex取得开头后,遍历以那个数为开头的数组中的每一个数
    • 比如[1,2,3],startindex=2, i 遍历[2,3]

 具体回溯过程不太懂

  • 39
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值