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
class Solution { //法1(更推荐,比第二种快很多):同一层递归相邻的重复数字直接跳过
public:vector<vector<int>> res;vector<int> path;vector<bool> used;void backtrack(vector<int>& nums) {// 终止条件:排列长度满了if (path.size() == nums.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {// 1. 已经用过这个元素 → 跳过if (used[i]) continue;// 2. ✅ 核心去重:同层重复元素,只保留第一个// 前面相同的数没用过 → 说明是同层,要跳过if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) {continue;}// 正常选数used[i] = true;path.push_back(nums[i]);backtrack(nums);path.pop_back();used[i] = false;}}vector<vector<int>> permuteUnique(vector<int>& nums) {used.resize(nums.size(), false);sort(nums.begin(), nums.end()); // ✅ 必须排序!backtrack(nums);return res;}
};
- 使用了同一层递归相邻的重复数字直接跳过这种去重方法必须提前排序,这里之所以和前面组合问题的判断条件不同是因为组合问题有startIndex,可以通过startIndex直接判断元素是否在同一层,现在每次都是从0开始选,只有有used数组来判断,如果used已经为true,则说明上一个元素在path里面,上一层(或者更前面的层),不是本层,不需要去重。如果不在path里面就是同一层,需要去重。
class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums,vector<bool>& used){if(path.size()==nums.size()){result.push_back(path);return;} for(int i=0;i<nums.size();i++){if(used[i]==true) continue;used[i] = true;path.push_back(nums[i]);backtracking(nums,used);path.pop_back();used[i] = false;}}vector<vector<int>> permuteUnique(vector<int>& nums) {vector<bool> used(nums.size(),false);backtracking(nums,used);set<vector<int>> myset(result.begin(),result.end());vector<vector<int>> finaResult(myset.begin(),myset.end());return finaResult;}
};
- 这种方法是一种笨方法,仅仅用于拿大部分分数(90%),一般很难通过全部样例,这道题对比以前的组合问题之所以不需要提前排序是因为组合问题中 1 4 2 4 可能出现1 4 2 和1 2 4这种情况(因为有startIndex的控制,排序后只会产生1 2 4 这种情况,set可以完全去重),set无法去重(组合不讲究顺序),但是排列无所谓,因为本身就是两种排列,若是怕弄混把排列问题也可以排序后再用set去重,并不会增加很多耗时,极小概率会因为这个排序丢失一个样例
