LeetCode0040-组合总和II

LeetCode0040-组合总和II

题目:

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

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

说明:

  • 所有数字(包括目标数)都是正整数。
  • 解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
	[1, 7],
	[1, 2, 5],
	[2, 6],
	[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
	[1,2,2],
	[5]
]

代码:

import java.util.*;

/**
 * 0040-组合总和II
 * 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
 * <p>
 * candidates 中的每个数字在每个组合中只能使用一次。
 * <p>
 * 说明:
 * <p>
 * 所有数字(包括目标数)都是正整数。
 * 解集不能包含重复的组合。
 * <p>
 * 示例 1:
 * <p>
 * 输入: candidates = [10,1,2,7,6,1,5], target = 8,
 * 所求解集为:
 * [
 * [1, 7],
 * [1, 2, 5],
 * [2, 6],
 * [1, 1, 6]
 * ]
 * <p>
 * 示例 2:
 * <p>
 * 输入: candidates = [2,5,2,1,2], target = 5,
 * 所求解集为:
 * [
 * [1,2,2],
 * [5]
 * ]
 */

/**
 * 类似于LeetCode0039-组合总和
 * 由于数字不能无限取,所以回溯的时候,从数组元素中取元素不能当前元素重复取
 * 同时,由于数组中可能包含重复元素,故需要剪枝
 */
class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        // 保存结果
        List<List<Integer>> result = new ArrayList<>();
        // 获取输入数组的长度
        int length = candidates.length;
        // 排序是为了提前终止搜索(剪枝操作)
        Arrays.sort(candidates);
        // 深度优先,回溯方法
        dfs(candidates, length, target, 0, new ArrayDeque<>(), result);
        return result;
    }

    /**
     * 回溯法(深度优先)
     *
     * @param candidates 数组输入
     * @param length     输入数组的长度
     * @param residue    剩余数值
     * @param begin      本轮搜索的起点下标
     * @param path       从根节点到任意节点的路径
     * @param result     结果集
     */
    private void dfs(int[] candidates, int length, int residue, int begin, Deque<Integer> path, List<List<Integer>> result) {
        if (residue == 0) {
            // 由于path 全局只使用一份,到叶子节点的时候需要保存结果
            result.add((new ArrayList<>(path)));
            return;
        }
        for (int i = begin; i < length; i++) {
            // 在数组有序的前提下,进行剪枝操作
            // 由于数组是排序好的,当前i的位置不满足添加,则后序的也不可能满足条件
            if (residue - candidates[i] < 0) {
                break;
            }
            // 去除结果集重复操作--剪枝解决重复元素可能出现的重复解
            if (i > begin && candidates[i] == candidates[i - 1]) {
                continue;
            }
            // 满足条件,将该数字添加进path中
            path.addLast(candidates[i]);
            // 继续调用回溯函数,同时修改搜索的起点下标,是为了解决数字不可以重复的问题
            dfs(candidates, length, residue - candidates[i], i + 1, path, result);
            // 回退
            path.removeLast();
        }
    }
}

/**
 * 测试类
 */
public class Study0040 {
    public static void main(String[] args) {
        List<List<Integer>> result = new Solution().combinationSum2(new int[]{10, 1, 2, 7, 6, 1, 5}, 8);
        for (List<Integer> list : result) {
            for (Integer number : list) {
                System.out.print(number + "\t");
            }
            System.out.println();
        }
    }
}

结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值