问题描述:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,[1,1,2]
have the following unique permutations:[1,1,2]
, [1,2,1]
, and [2,1,1]
.
原问题链接:https://leetcode.com/problems/permutations-ii/
问题分析
这个问题其实和前面的那个问题差不多,不过是一个针对有重复元素的情况进行处理,需要去掉那些重复的记录。在之前的文章里也对这种情况进行了分析。我们可以用递归的方式来实现,不过这种方式相对来说稍微复杂了一点,而且效率也不高。最有意思的地方是我们前面列举的字典序方法是可以处理重复元素的情况,它可以保证返回的元素集合已经去除了重复的情况。所以说,把前面的代码直接搬过来就可以了:
public class Solution {
public List<List<Integer>> permuteUnique(int[] num) {
Arrays.sort(num);
List<List<Integer>> lists = new ArrayList<List<Integer>>();
lists.add(appendList(num));
while(true) {
int start = findStart(num);
if(start == -1) break;
int end = findEnd(num, start);
if(end == -1) break;
swap(num, start, end);
reverse(num, start + 1, num.length - 1);
lists.add(appendList(num));
}
return lists;
}
private List<Integer> appendList(int[] num) {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < num.length; i++)
list.add(num[i]);
return list;
}
private int findStart(int[] num) {
for(int i = num.length - 2; i >= 0; i--)
if(num[i] < num[i + 1])
return i;
return -1;
}
private int findEnd(int[] num, int l) {
for(int i = num.length - 1; i > l; i--)
if(num[i] > num[l])
return i;
return -1;
}
private void reverse(int[] num, int l, int r) {
while(l < r) {
swap(num, l, r);
l++;
r--;
}
}
private void swap(int[] num, int i, int j) {
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}
为什么这种方式可以处理重复元素的情况呢?因为我们之前的字典序构造里,是针对元素排列的递增和递减情况来处理的。针对相等元素的情况则直接跳过去了。具体的细节可以看前面文章里的分析。