排列组合是笔试面试中常见的题目类型,普通排列组合难度较简单,但如果包含去重问题时候,还是有些规律可循的
Leetcode47 全排列 II
**题目描述**
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
**示例**
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
首先说为何会产生重复问题,以示例来说,当索引从0开始会出现1,1,2的情况,而当首先选择第2个1时候,还有可能选择第一个1,这样还是1,1,2,导致了,重复问题的出现,当然你也可以在最终结果集中用list的contains方法去重,不过方法复杂度较高,直接在递归过程中去重,复杂度较低。
算法实现思路
首先进行排序,如果两个数相等,只有在前一个数已经加入到结果中时候,才能加第二个数,
所以还是以示例来说,就不存在先加入第二个1,再加入第一个1的情况了,解决了去重问题
实现代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
boolean[] visited;
public List<List<Integer>> permuteUnique(int[] nums) {
visited = new boolean[nums.length];
Arrays.sort(nums);
dfs(nums,new ArrayList<>());
return res;
}
private void dfs(int[] nums,ArrayList<Integer> tmp){
if(tmp.size() == nums.length){
//if(!res.contains(tmp)) 可以在这去重,但复杂度较高,用时300ms
res.add(new ArrayList<>(tmp));
return;
}
for(int i = 0;i < nums.length;i++){
if(i > 0 && nums[i] == nums[i-1] && !visited[i-1]) continue; //按照上述算法去重,用时2ms
if(!visited[i]){
visited[i] = true;
tmp.add(nums[i]);
dfs(nums,tmp);
visited[i] = false;
tmp.remove(tmp.size() - 1);
}
}
}
}
Leetcode 40 组合总和
**题目描述**
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
**示例**
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
为什么会产生重复,首先先排序,数组变为1,2,2,2,5,target = 5,那么在选1,2,2时候很明显有多种选择方法,那么如何去重呢。
算法思路
当出现重复数字时候,只有在首次进入for循环,即i == index时候才可以加入,如果是回溯之后并且重复则不加入。
代码如下
class Solution {
int[] candidates;
int n,target;
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
this.candidates = candidates;this.n = candidates.length;this.target = target;
dfs(0,0,new ArrayList<>());
return res;
}
public void dfs(int index,int sum,List<Integer> tmp){
if(index > n) return;
if(sum > target) return;
if(sum == target){
//if(!res.contains(tmp) 同样的可以在这选择去重,但复杂度高不可取
res.add(new ArrayList<>(tmp));
return;
}
for(int i = index;i < n;i++){
if(i != index && candidates[i] == candidates[i-1]) continue; //在这选择去重,i != index都进行了回溯
tmp.add(candidates[i]);
sum += candidates[i];
dfs(i+1,sum,tmp);
sum -= candidates[i];
tmp.remove(tmp.size()-1);
}
}
}
以上,就是对排列组合中去重问题的总结。