全排列 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 {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<bool> used(nums.size(),false);
backtracking(nums,used);
return res;
}
void backtracking(vector<int>& nums,vector<bool>& used)
{
if(path.size()==nums.size())
{
res.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(used[i]) continue;
if(i>0&&nums[i]==nums[i-1]&&used[i-1]) continue;
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,used);
used[i]=false;
path.pop_back();
}
return;
}
};
解法二:
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<bool> used(nums.size(),false);
backtracking(nums,used);
return res;
}
void backtracking(vector<int>& nums,vector<bool>& used)
{
if(path.size()==nums.size())
{
res.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(used[i]) continue;
if(i>0&&nums[i]==nums[i-1]&&!used[i-1]) continue;
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,used);
used[i]=false;
path.pop_back();
}
return;
}
};
做题小结:
解针对法一:
主要还是在去重上面需要下功夫:
1.首先需要注意同层不能重复使用,因此需要
if(used[i]) continue;
2.而要做到结果中不含重复数组,则必须要保证在同层遍历中,已经使用过的“数值”只使用一次,因此需要
if(i>0&&nums[i]==nums[i-1]&&used[i-1]) continue;
这里需要注意used[i-1]很必要,否则不能保证至少有一个数值被使用
针对解法二:
在去重时需要深刻理解used为true和为false时分别代表什么
- used[i - 1] == true,说明同一树支nums[i - 1]使用过 ; used[i - 1] == false,说明同一树层nums[i - 1]使用过 ; 如果同一树层nums[i - 1]使用过则直接跳过。因此可以看到解法二跟解法一的区别就在于used[i-1]要求变成了false,但结果却一样
- 对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
- 要理解used为false时同层被遍历,要明白i是从0开始依次遍历的。
