给定一个数组 candidates 和一个目标数 target

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。

前言

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

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

注意:解集不能包含重复的组合。

解题思路

此处撰写解题思路 本来小编想的是这题和子集II一模一样,就是加了一个条件总和得等与target,但是那种按位去与或就限定了长度不能超过32,毕竟按位的时候对应着32位int的0和1.

所以就只能回溯法去求解了,题目要求每个数字只能用一次且求的结果是组合,那就与子集顺序无关,是要去重的。这里去重使用used数组,其实还是回到了子集II问题,不能说很像吧,简直是一模一样。那这里就用回溯去解决吧,毕竟官方为这个题定义就是想让大家练习回溯。

回溯其实不难,但这个题难的是怎么去重,怎么保证每个元素只使用一次,可以想象一下,举个例子,[1,2,2,5]子集[1,2,5]和[1,2,5]分别是取第一个2和第二个2得到的子集,这就是重复的,要去重,这就属于同一层级之间的重复,但对于[1,2,2,5]是由[1,2,5]往深一层次得到的子集,就属于同一树枝,所以对于同一层级重复是不允许的,而同一树枝重复则是可以的,这里重复指的不是整个子集一模一样,而是2这个元素重复,要搞清楚,就是为什么[2],[2]重复不行,但是在加一个2得到[2,2]就可以。这里很关键。

然后就是创建used数组,默认都是false也就是意味着当前对应下标元素没使用过,每次深入下一层,记得是start下标+1,这就解决了元素只能使用一次的问题。最后记得怎么递归下去的,就得怎么回来,毕竟很多变量在后面的递归还要用的。

代码

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> arr=new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        boolean[] used=new boolean[candidates.length];
        backtracking(candidates,used,0,0,target);
        return res;
    }
​
public void backtracking(int[] candidates,boolean[] used,int start,int sum,int target){
    if(sum>target){
        return;
    }
    if(sum==target){
        res.add(new ArrayList<>(arr));
        return;
    }
    for(int i=start;i<candidates.length;i++){
        if(i>0&&candidates[i]==candidates[i-1]&&!used[i-1]){//同层级的重复是不允许的
            continue;
        }
        sum+=candidates[i];
        arr.add(candidates[i]);
        used[i]=true;
        backtracking(candidates,used,i+1,sum,target);
        sum-=candidates[i];
        arr.remove(arr.size()-1);
        used[i]=false;
    }
}
复制代码

}\

おすすめ

転載: juejin.im/post/7031467936661372965