题目
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解及思路
重复情况判断
枚举出所有结果集,可以发现,在①步骤中重复的两个数列出的结果可能情况相同,及(1,1,0)及他们的子情况一致,这时可以摒弃其中一个,在②中,(2,0,0)子情况中两次注入元素1的子情况一致,也可以摒弃一个。
由此可知,在一个位置使用不同下标但相同值的元素情况会重复,判断时要将这种情况排除,及上面程序中先为nums数组进行排序 Arrays.sort(nums) ,再在后面的判断中使用 i>0&&nums[i]==nums[i-1]&&!flag[i-1] 两个&&旁的代码意思分别为:
Ⅰ、i>0 非第一个,因为后续才会和前面的重复,且i=0时会导致nums[i-1]越界。
Ⅱ、nums[i]==nums[i-1] 前面做过排序,只需和前一个比较就知道是否是重复的数。
Ⅲ、!flag[i-1] 判断前一个相等的数是否使用过,要求前一个使用过才可以使用后一个数,这样可以避免重复。
而前面 flag[i] 是判断当前元素是否被使用,未被使用过才可以注入数组,
源码
class Solution {
boolean[] flag;
int len;
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
List<Integer> path = new ArrayList<>();
len = nums.length;
Arrays.sort(nums);
flag = new boolean[len];
dfs(ret,path,0,nums);
return ret;
}
private void dfs(List<List<Integer>> ret,List<Integer> path,int index,int[] nums){
if(index==len){
ret.add(new ArrayList<Integer>(path));
return;
}
for(int i = 0;i<len;++i){
if(flag[i]||i>0&&nums[i]==nums[i-1]&&!flag[i-1]){
continue;
}
path.add(nums[i]);
flag[i] = true;
dfs(ret,path,index+1,nums);
flag[i] = false;
path.remove(index);
}
}
}