47 全排列 II
给定一个可包含重复数字的序列 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
显然,对于一组重复数字可以产生 $C^n_n$ 种重复方案,
我们观察遍历过程有如下规律

只有第一种方案数字被选择的过程在原数组中是依次从左到右逐个选择的,也就是 nums[i]==nums[i-1]&&vis[i-1]时,后一个才能被访问。那么,可以据此将其他可能的选择顺序排除也就是continue
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
ranges::sort(nums);
int n = nums.size();
vector<vector<int>> ans;
vector<int> path(n); // 所有排列的长度都是 n
vector<int> on_path(n); // on_path[j] 表示 nums[j] 是否已经填入排列
// i 表示当前要填排列的第几个数
auto dfs = [&](this auto&& dfs, int i) -> void {
if (i == n) { // 填完了
ans.push_back(path);
return;
}
// 枚举 nums[j] 填入 path[i]
for (int j = 0; j < n; j++) {
// 如果 nums[j] 已填入排列,continue
// 如果 nums[j] 和前一个数 nums[j-1] 相等,且 nums[j-1] 没填入排列,continue
if (on_path[j] || j > 0 && nums[j] == nums[j - 1] && !on_path[j - 1]) {
continue;
}
path[i] = nums[j]; // 填入排列
on_path[j] = true; // nums[j] 已填入排列(注意标记的是下标,不是值)
dfs(i + 1); // 填排列的下一个数
on_path[j] = false; // 恢复现场
// 注意 path 无需恢复现场,因为排列长度固定,直接覆盖就行
}
};
dfs(0);
return ans;
}
};

浙公网安备 33010602011771号