![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ab91b4e43aa5855e507f57d6ba936d92.png)
此题为46题的衍生题,在46题的基础上,加上了是否重复的判断,除此之外完全一样。
1. 暴力回溯
解题思路:时间复杂度O(
n
n
n^n
nn),但是严格来说只到了O(
n
∗
n
!
n*n!
n∗n!)。空间复杂度O(n) |
---|
- 在46题的基础上增加一些判断是否重复的操作
- 首先我们先将数组排序,这样我们就能通过两个相邻值的比较,确定当前值是否是一个重复的值(不止一个它)
- 我们进行全排列时,每个位置可以选择任何不同的值,但是现在有重复的值,就必须确保同一个位置,重复的值只选一次
- 所以进行全排列时,通过比较相邻的值就可以判断了。但是必须是有序数组才行(重复数字会都挨在一起)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/705015d9a33d676948f797be2ab8530f.png)
int[] nums;
boolean[] numsFlag;
int len;
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
this.nums = nums;this.len = nums.length;
this.numsFlag = new boolean[len];
ArrayList<Integer> records = new ArrayList<>();
backTracking(records);
return ans;
}
public void backTracking(List<Integer> records){
if(records.size() == len) ans.add(new ArrayList<>(records));
else{
for(int i = 0;i<len;i++){
if(this.numsFlag[i]==true || (i>0 && nums[i] == nums[i-1] && this.numsFlag[i-1] == false) ) continue;
this.numsFlag[i] = true;
records.add(nums[i]);
backTracking(records);
this.numsFlag[i] = false;
records.remove(records.size()-1);
}
}
}
2. 分区法+回溯
解题思路:时间复杂度O(
n
∗
n
!
∗
l
o
g
2
n
n*n!*log_2{n}
n∗n!∗log2n),其中
l
o
g
2
n
log_2{n}
log2n是判断是否重复的时间开销。空间复杂度O(n) |
---|
- 含有重复的元素序列,进行全排列,这个方法就不太好用,因为处理重复很麻烦
- 所以这里只能通过笨办法,每次选择数字判断是否重复时,从当前位置可选值中,依次遍历判断我们当前要选的数字是否之前就存在过
- 这个算法依然不需要flag数组标志数字是否已经选择过,也不需要事先排序。
- 与46题代码几乎完全照搬,只单纯加了一个循环遍历数组,判断是否重复的方法而已。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0f188b36828eefcccbea15ab7f550435.png)
class Solution {
int[] nums;
int len;
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> permuteUnique(int[] nums) {
this.nums = nums;this.len = nums.length;
dfs(0);
return ans;
}
private void dfs(int idx) {
if (idx == len) {
List<Integer> result = new ArrayList<>();
for (int num: nums) result.add(num);
ans.add(result);
}
for (int i = idx; i < len; i++) {
if (isRepeat(nums, idx, i)) continue;
swap(nums, idx, i);
dfs( idx + 1);
swap(nums, idx, i);
}
}
private boolean isRepeat(int[] nums, int idx, int i) {
while (idx < i) if (nums[idx++] == nums[i]) return true;
return false;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}