解法一:回溯
和普通的全排列一样,都可以使用回溯法,唯一的区别在于需要处理重复元素之前位置互换带来的冗余。令重复元素之前保持某种固定的顺序是一种解决冗余的思路。
class Solution {
private List<List<Integer>> ans;
private boolean[] isVisited;
public List<List<Integer>> permuteUnique(int[] nums) {
int n = nums.length;
ans = new LinkedList<>();
isVisited = new boolean[n];
// 排序使得重复元素连在一起
Arrays.sort(nums);
Integer[] arr = new Integer[n];
permute(n, nums, 0, arr);
return ans;
}
private void permute(final int N, final int[] nums, int index, Integer[] arr) {
if (index == N) {
List<Integer> list = new ArrayList(N);
Collections.addAll(list, arr);
ans.add(list);
return;
}
for (int i = 0; i < N; ++i) {
if (isVisited[i]) {
continue;
}
// 对于重复数字, 在全排列中出现的次序必须与原来的顺序保持一致
// 因此如果原来排在它前面的重复数字还没有被使用, 它也不能加入全排列
if ((i > 0) && (nums[i] == nums[i - 1]) && (!isVisited[i - 1])) {
continue;
}
arr[index] = nums[i];
isVisited[i] = true;
permute(N, nums, index + 1, arr);
isVisited[i] = false;
}
}
}