【Leetcode之回溯】0040 组合总和 II

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/combination-sum-ii

实现语言:Java

文章记录的是第一次做力扣题时的代码,之后做题的代码放在GitHub上了,由于博客中的文章有点多,挨个修改费时费力,博客中写的有关力扣的文章和GitHub中的代码并不完全对应。力扣题GitHub地址

题目

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

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

说明:

  • 所有数字(包括目标数)都是正整数。
  • 解集不能包含重复的组合

示例

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
  [1,2,2],
  [5]
]

方法:回溯

以数组 candidates = [2,5,2,1,2], target = 5 为例,访问的节点如下图所示。其中,绿色框表示当前节点的值,红色框表示不再继续向下访问,F 表示当前路径上的所有值的总和大于目标值,T 表示当前路径上的所有值的总和等于目标值。

第一次访问,以数组中第一个节点 2 为起点。其中,列表 [2,1,2][2,2,1] 重复,不再添加。

第二次访问,以数组中第二个节点 5 为起点。

第三次访问,以数组中第三个节点 2 为起点。

第四次访问,以数组中第四个节点 1 为起点。

第五次访问,以数组中第五个节点 2 为起点。

代码实现

import java.util.List;
import java.util.LinkedList;
import java.util.Set;
import java.util.HashSet;
import java.util.Comparator;
class Solution {
    Set<List<Integer>> set = new HashSet<>();  // 重复的列表不添加
    Stack<Integer> stack = new Stack<>();
    int sum = 0;
    // 比较器
    Comparator<Integer> comparator = new Comparator<Integer>() {
        public int compare(Integer o1, Integer o2) {
            return o1-o2;
        }
    };

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        for (int i=0; i<candidates.length; i++) {
                stack.push(i);
                sum += candidates[i];
                backtracking(candidates, target, i);
                sum -= candidates[stack.peek()];
                stack.pop();
        }

        List<List<Integer>> res = new LinkedList<>();
        for (List<Integer> tmp : set) {
            res.add(tmp);
        }
       return res;
    }

    public void backtracking (int[] candidates, int target, int i) {
        if (sum > target) return;
        if (sum == target) {
            List<Integer> tmp = new LinkedList<>();
            for (int k: stack)
                tmp.add(candidates[k]);
            tmp.sort(comparator);
            set.add(tmp);
            return;
        }
        // 访问下一层的邻接点
        for (int j=i+1; j<candidates.length; j++) {
            stack.push(j);
            sum += candidates[j];
            backtracking(candidates, target, j);
            sum -= candidates[stack.peek()];
            stack.pop();
        }
    }

}

执行用时:1293 ms

内存消耗:39.4 MB

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值