LeetCode_82_CombinationSum


1. question: 组合总和(中等)

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

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/combination-sum

示例 1:

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

示例 2:

1
2
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

1
2
输入: candidates = [2], target = 1
输出: []

提示:

1
2
3
4
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都 互不相同
1 <= target <= 500

2. answers

这道题猛地一看,还是比较灵活的。首先是给定了数组和target,求解数组中和为target的组合。

  1. 对组合的元素是否重复无要求
  2. 对组合的元素个数无要求
  3. 要求结果中的组合不重复,即至少有一个数字的频率不一样

思路总体上和组合一样,不过,这里将数组进行升序排列,方便后续剪枝;另外,将target每次减去组合中的元素值,不设置元素和变量sums。最开始想的时候,因为允许元素重复使用,所以我在做的时候没有限制每个组合的元素的下标取值范围。因此这肯定会出现重复结果的。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Solution_0081 {

public List<List<Integer>> result = new ArrayList<>();

public LinkedList<Integer> group = new LinkedList<>();

public void recurCom(int[] candidates, int target) {

// 递归终止
if(target == 0) {
result.add(new ArrayList<>(group));
return;
}

// target的每个子元素均可选择数组中的任意元素
for (int i = 0; i < candidates.length; i++) {

// 因为数组已经排序了,此时,如果剩余target已经小于当前元素,说明一定小于后续的元素,因此,直接终止本层元素的递归,返回上一层。
if(target < candidates[i]) return;

// 将当前元素加入结果中
group.add(candidates[i]);
target -= candidates[i];

// 递归集合中的下一个元素
recurCom(candidates, target);

// 回溯上一个操作
group.removeLast();
target += candidates[i];
}
}

public List<List<Integer>> combinationSum(int[] candidates, int target) {

// 对数组升序
Arrays.sort(candidates);

recurCom(candidates, target);

return result;
}

public static void main(String[] args) {
System.out.println();

// int[] candidates = {2, 3, 6, 7};
int[] candidates = {2, 3, 5};

Solution_0081 s = new Solution_0081();

List<List<Integer>> result = s.combinationSum(candidates, 8);

for(List<Integer> list: result) {

for(Integer i: list)
System.out.print(i + "\t");

System.out.println();
}
}
}

但是,因为一个组合中允许元素重复使用。所以,只是在一层循环中,不限制元素的使用。但是在不同的组合中,是限制下标的,这样才不会出现重复组合。

以[2, 3, 5, 6]为例,target=8。

  1. 第一个集合,取2,后续的元素,可以在下标[0, 3]之间任意。即元素可重复。
  2. 但是当第二个集合的时候,第一个元素为3,后续的元素,只能是下标[1, 3]之间任意取。因为包含2且包含3的情况,已经在第一个集合中取遍了。
  3. 所以,不同集合之间的下标还是有限制的。

代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Solution_0081_02 {

public List<List<Integer>> result = new ArrayList<>();

public LinkedList<Integer> group = new LinkedList<>();

public void recurCom(int[] candidates, int target, int startIndex) {

// 递归终止
if(target == 0) {
result.add(new ArrayList<>(group));
return;
}

// target的每个子元素均可选择数组中的任意元素
for (int i = startIndex; i < candidates.length; i++) {

// 因为数组已经排序了,此时,如果剩余target已经小于当前元素,说明一定小于后续的元素,因此,直接终止本层元素的递归,返回上一层。
if(target < candidates[i]) return;

// 将当前元素加入结果中
group.add(candidates[i]);
target -= candidates[i];

// 递归集合中的下一个元素,注意在以candidate[i]的开头的集合中,是可重复取元素的,因此,后续的startIndex仍为i,而不是i+1
recurCom(candidates, target, i);

// 回溯上一个操作
group.removeLast();
target += candidates[i];
}
}

public List<List<Integer>> combinationSum(int[] candidates, int target) {

// 对数组升序
Arrays.sort(candidates);

recurCom(candidates, target, 0);

return result;
}

public static void main(String[] args) {
System.out.println();

int[] candidates = {2, 3, 6, 7};
// int[] candidates = {2, 3, 5};

Solution_0081_02 s = new Solution_0081_02();

List<List<Integer>> result = s.combinationSum(candidates, 7);

for(List<Integer> list: result) {

for(Integer i: list)
System.out.print(i + "\t");

System.out.println();
}
}
}

3. 备注

参考力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 (leetcode-cn.com)代码随想录 (programmercarl.com)


文章作者: 浮云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 浮云 !
  目录