代码随想录算法训练营第二十七天 |39. 组合总和40.组合总和II 131.分割回文串

文章介绍了如何使用Java编程语言,通过回溯法来解决组合总和的问题,包括无重复元素的组合总和和有重复元素但不允许重复组合的组合总和II。在解题过程中,重点在于排序、剪枝和去重策略,以及递归回溯的实现细节。
摘要由CSDN通过智能技术生成

39. 组合总和

给你一个 无重复元素的整数数组 candidates和一个目标整数 target,找出 candidates  中可以使数字和为目标数 target的 所有 **不同组合,并以列表形式返回。你可以按 任意顺序  返回这些组合。

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。

回溯三部曲:

  1. 确定参数和返回值:返回值为void,参数为数组candidates,目标和target,记录sum,选取开始的索引startIndex

  2. 终止条件:sum==target将结果添加到relsut中返回

  3. 单层搜索逻辑

    处理节点、递归、回溯

    其中剪枝处理,如果sum + candidates[i] > target就会不符合条件

class Solution {
  List<List<Integer>> reslut=new ArrayList<>();
    List<Integer> res=new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates); // 先进行排序
        trackbacking(candidates,target,0,0);
        return reslut;
    }
    public void trackbacking(int[] candidates,int target,int sum,int startIndex){
        if(sum==target){
            reslut.add(new ArrayList<>(res));
            return;
        }
        for(int i=startIndex;i<candidates.length && sum + candidates[i] <= target;i++){
            res.add(candidates[i]);
            trackbacking(candidates,target,sum+candidates[i],i);
            res.remove(res.size()-1);
        }
    }
}

40. 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

**集合(数组candidates)有重复元素,但还不能有重复的组合,**所以这道题的关键是去重

回溯三部曲:

  1. 参数和返回值:返回值为void,参数为candidates,target,sum,startIndex

  2. 递归终止条件:sum==target

  3. 单层搜索逻辑

    为了进行去重我们定义了一个boolean数组 used,首先将数组填充为false

    这里首先需要考虑去重candidates[i]==candidates[i-1]&&!used[i-1] 跳过本次循环

    处理节点:处理节点是需要将used[i]设置为true表明这个数出现过

    递归

    回溯:回溯需要将used[i]设置为false,在进行下一层处理

class Solution {
    List<List<Integer>> reslut=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    boolean[] used;
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        used = new boolean[candidates.length];
        Arrays.fill(used,false);
        Arrays.sort(candidates);
        trackbacking(candidates,target,0,0);
        return reslut;
    }
    public void trackbacking(int[] candidates,int target,int sum,int startIndex){
        if(sum==target){
            reslut.add(new ArrayList<>(path));
            return;
        }
        for(int i=startIndex;i<candidates.length&&sum + candidates[i] <= target;i++){
            if(i>0&&candidates[i]==candidates[i-1]&&!used[i-1]){
                continue;
            }
            used[i]=true;
            sum+=candidates[i];
            path.add(candidates[i]);
            trackbacking(candidates,target,sum,i+1);
            used[i]=false;
            path.remove(path.size()-1);
            sum-=candidates[i];
        }
    }
}

Arrays.fill(arrayname,value) 方法,用于数组填充

131. 分割回文串

给你一个字符串 s,请你将 **s **分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。

切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。

回溯三部曲:

  1. 参数和返回值:返回值为void,参数为字符串s,strtindex用来记录分割点

  2. 终止条件:如果切割点strtindex>=s.length()

  3. 单层搜索逻辑

    首先需要判断截取字符串是否为回文,如果为回文用substring截取字符串并添加到path当中

    回溯

    递归

判断是否为回文:只需两个指针,一个从起点开始遍历,一个从末尾开始遍历,如果字符不相等则为false,若相等则为true

class Solution {
    List<List<String>> reslut=new ArrayList<>();
    List<String> path=new ArrayList<>();
    public List<List<String>> partition(String s) {
        trackbacking(s,0);
        return reslut;
    }
    public void trackbacking(String s,int starIndex){
        if(starIndex>=s.length()){
            reslut.add(new ArrayList<>(path));
            return;
        }
        for(int i=starIndex;i<s.length();i++){
            if(isPalindrome(s,starIndex,i)){
                String str=s.substring(starIndex,i+1);
                path.add(str);
            }else{
                continue;
            }
            trackbacking(s,i+1);
            path.remove(path.size()-1);
        }

    }

    //判断回文
    private boolean isPalindrome(String s,int startIndex,int endIndex){
        for(int i=startIndex,j=endIndex;i<j;i++,j--){
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值