【LeetCode-回溯】全排列 II
题目描述
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
题目描述: https://leetcode-cn.com/problems/permutations-ii/
做这题之前可以先做一下全排列。
思路
这题和全排列基本是一样的。这题中的数组可能包含重复的数字,所以牵扯到去重的操作。为什么会出现重复呢?举个例子,假如数组是[1,1,2],我们首先使用第一个数字1进行递归,会得到两个排列[1,1,2]和[1,2,1];然后我们再使用第二个数字1进行递归,会得到两个排列[1,1,2]和[1,2,1];最后使用第三个数字2进行递归,得到两个排列[2,1,1]和[2,1,1]。可以看到使用第二个数字1进行递归和使用第三个数字2进行递归会产生重复的结果。这两种会产生重复结果的情况的共同点是:在同一层递归使用了相同的数字。例如第一个数字1是第1层的第一个节点,此时这层只有这一个节点,不存在重复的情况,所以可以递归。而第二个1是第1层的第2个节点,此时这一层已经有一个1了,所以就不能继续递归了(剪枝)。使用第3个数字2进行递归也是类似的。
在实际操作的时候,我们先将数组排序,然后在递归的时候比较当前值是否和前一个相等,如果相等并且前一个值已经加入到排列中了,那就将当前值跳过。代码如下:
class Solution {
public:
vector<vector<int>> ans;
vector<vector<int>> permuteUnique(vector<int>& nums) {
if(nums.empty()) return {{}};
vector<int> track;
vector<int> visit(nums.size(), 0);
sort(nums.begin(), nums.end()); // 先排序有助于去重
dfs(nums, 0, track, visit);
return ans;
}
void dfs(vector<int> nums, int start, vector<int> track, vector<int> visit){
if(track.size()==nums.size()){
ans.push_back(track);
return;
}
for(int i=0; i<nums.size(); i++){
if(i>0 && nums[i]==nums[i-1] && visit[i-1]) continue; // 去重操作
if(!visit[i]){
track.push_back(nums[i]);
visit[i] = 1;
dfs(nums, 0, track, visit);
track.pop_back();
visit[i] = 0;
}
}
}
};
这篇题解对于去重的操作讲的很好。
相关题目
1、全排列:https://www.cnblogs.com/flix/p/12771867.html
2、子集:https://www.cnblogs.com/flix/p/12769354.html
3、子集II:https://www.cnblogs.com/flix/p/12770371.html