一、题目
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
二、思路
- 若不存在重复元素,全排列用一个v数组来控制每个位置数是否已经访问过,若没有访问过则可以使用当前数,如访问过则跳过,最后知道所有数都访问过则找到一个答案。
- 现在存在重复元素,若依旧使用上面的思路,那么同一个数可能会填入相同的位置多次,如3个重复的1为1a 1b 1c, 那么组合可能有1a 1b 1c, 1a 1c 1b, 1b 1a 1c等等。那么我们可以添加一个规则,限定我们只会出现1a … 1b…1c这种顺序的排列,即压迫使用1c,那么必须保证1a 1b都使用过,如何保证呢,我们可以将nums数组进行排序,排序后所有相同的数排在一起,那么当遍历到一个数若和前面的数相同,那么必须判断前面的数是否使用过,使用过才能使用当前的数,如要使用1b,那么必须使用过1a, !vis[i-1]就可以看做1a是否使用过。
三、代码
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> ans;
vector<int> t;
vector<bool> v(nums.size());
sort(nums.begin(), nums.end());
dfs(t, nums, 0, ans, v);
return ans;
}
void dfs(vector<int>& t, vector<int>&nums, int idx, vector<vector<int>>& ans, vector<bool>& v) {
if (idx == nums.size()) {
ans.push_back(t);
return;
}
for (int i = 0; i < nums.size(); i++) {
//若当前位置已经访问了掠过
//若当前位置的数与前面的数相同,但是前面的数还没有访问过,那么便不能用该数
//这样就可以保证相同的数的顺序相同 如: 1a ...1b...1c
if (v[i] || (i > 0 && nums[i] == nums[i - 1]) && !v[i - 1]) continue;
t.push_back(nums[i]);
v[i] = true;
dfs(t, nums, idx + 1, ans, v);
v[i] = false;
t.pop_back();
}
}
};