40.组合总和Ⅱ
「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。
难度:mid 来源:力扣(LeetCode)
题目:
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8, 输出: [ [1,1,6], [1,2,5], [1,7], [2,6] ]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5, 输出: [ [1,2,2], [5] ]
提示:
- 1 <= candidates.length <= 100
- 1 <= candidates[i] <= 50
- 1 <= target <= 30
思路:
该题中的思路与lc39相同,但是根据题目可知,本题需要进行去重操作(解集不能包含重复的组合),这也是这题目中的难点。可以使用map或者set等.但是非常容易超时,比如我使用的List中的contains函数操作:
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
int tt = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int len = candidates.length;
Arrays.sort(candidates); //[1,1,2,5,6,7,10]
combina(candidates,len,target,0);
return res;
}
void combina(int[] candidates,int len,int target,int index){
if(target < 0) return;
List<Integer> e = new ArrayList<>(path);
if(res.contains(e)) return;
if(target == 0){
res.add(e);
return;
}
for(int i = index; i < len; i++){
path.add(candidates[i]);
combina(candidates,len,target-candidates[i],i+1);
path.removeLast();
}
}
}
直接就超了:
172 / 175 个通过测试用例
状态:超出时间限制
提交时间:1 小时前
最后执行的输入:
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
30
既然不能在结果集中去重,那么只能在递归的过程中。如何去重呢?代码如下:
for(int i = index; i < len; i++){
if(i>index&&candidates[i]==candidates[i-1])
{
continue;
}
}
解释其去重原理:引自于leetcode中的Allen大佬。
但是个人看完还是不太明白,为什么i会出现比index大的情况?
于是只能手动debug一下:
这里是个人的理解视频,有什么问题欢迎指正。
完整代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int len = candidates.length;
Arrays.sort(candidates); //[1,1,2,5,6,7,10]
combina(candidates,len,target,0);
return res;
}
void combina(int[] candidates,int len,int target,int index){
if(target < 0) return;
List<Integer> e = new ArrayList<>(path);
if(target == 0){
res.add(e);
return;
}
for(int i = index; i < len; i++){
if(i>index&&candidates[i]==candidates[i-1])
{
continue;
}else{
path.add(candidates[i]);
combina(candidates,len,target-candidates[i],i+1);
path.removeLast();
}
}
}
}
调试代码:
package com.lc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class lc40 {
static List<List<Integer>> res = new ArrayList<>();
static LinkedList<Integer> path = new LinkedList<>();
public static void main(String[] args) {
int[] candidates = new int[]{2,5,2,1,2};
int target = 5;
combinationSum2(candidates,target);
}
public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
int len = candidates.length;
Arrays.sort(candidates); //[1,1,2,5,6,7,10]
combina(candidates,len,target,0);
return res;
}
static void combina(int[] candidates, int len, int target, int index){
if(target < 0) return;
List<Integer> e = new ArrayList<>(path);
if(res.contains(e)) return;
if(target == 0){
res.add(e);
return;
}
for(int i = index; i < len; i++){
if(i>index&&candidates[i]==candidates[i-1])
{
continue;
}else{
path.add(candidates[i]);
combina(candidates,len,target-candidates[i],i+1);
path.removeLast();
}
}
}
}