leetcode40.组合总和II——学习笔记

题目:力扣https://leetcode-cn.com/problems/combination-sum-ii/

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        Deque<Integer> path = new ArrayDeque<Integer>();

        Arrays.sort(candidates);
        backTrack(candidates,target,0,path,ans);
        return ans;
    }

    private void backTrack(int[] candidates,int target,int begin,Deque<Integer> path,List<List<Integer>> ans){
        //出口
        if(target == 0){
            ans.add(new ArrayList<>(path));
            return;
        }

        for(int i=begin;i<candidates.length;i++){
            // 大剪枝
            if (target - candidates[i] < 0) {
                break;
            }
            //小剪枝
            if (i>begin && candidates[i]==candidates[i-1]) {
                continue;
            }
            path.addLast(candidates[i]);
            backTrack(candidates,target-candidates[i],i+1,path,ans);
            path.removeLast();
        }
    }
}

 

思路:这题和leetcode39.组合总和 大同小异。不同点点:leetcode37中的candidates[]数组中的元素可以重复用,而这题中的candidates[]数组中的元素中能用一次。一开始我想直接删掉那些元素数量超额的答案,但是感觉这题就变查重题目而且时间复杂度会很大。因此,套用39题中的大致结构,学习题解然后改造原有的那份代码。大概思路仍然是回溯,修改的地方主要是增加了剪枝。

1.主方法有些许改动,因为采取了剪枝的方法(后面详述),所以不需要用HashSet去重,所以那部分的代码删去了。为了方便后续剪枝,再调用backTrack()之前,先把candidates[]数组排序。backTrack()仍然一个递归的方法,只是里面添加了些剪枝条件。

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    Deque<Integer> path = new ArrayDeque<Integer>();

    Arrays.sort(candidates);
    backTrack(candidates,target,0,path,ans);
    return ans;
}

2.写一个回溯的方法,基本就是leetcode39.组合总和复制粘贴。相比于leetcode39.组合总和candidates中元素可以多次使用,本题每个元素只能使用一次,因此,不得不多了一个begin变量记录遍历数组的起始位置。出口的判断条件仍然不变。增加了大小剪枝两部分代码:大兼职,即使当target-candidate[i]<0时,candidate[i]、candidate[i+1]、candidate[i+2]和candidate[i+n]等等都不要继续判断了,这些“枝”都会被剪去;小剪枝,当candidates[i]==candidates[i-1]时可以把这条“枝”剪去,这样就避免了重复解。但是这些操作都需要一个条件:candidates[]有序,所以前面需要再调用backTrack()之前将数组升序排序。与leetcode39.组合总和不一样的地方还有一个,39题递归调用backTrack()是传入同一个candidates[]数组,这题一个元素只能用一次,因此递归调用的时候需要传入一个begin表示遍历candidateas[]数组的起始位置,并且每一次递归都需要让begin前进一步,即i+1。

private void backTrack(int[] candidates,int target,int begin,Deque<Integer> path,List<List<Integer>> ans){
    //出口
    if(target == 0){
        ans.add(new ArrayList<>(path));
        return;
    }
        
    for(int i=begin;i<candidates.length;i++){
        // 大剪枝
        if (target - candidates[i] < 0) {
            break;
        }
        //小剪枝
        if (i>begin && candidates[i]==candidates[i-1]) {
            continue;
        }
        path.addLast(candidates[i]);
        backTrack(candidates,target-candidates[i],i+1,path,ans);
        path.removeLast();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hokachi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值