leetcode 47. 全排列 II---回溯篇6
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode 47. 全排列 II---回溯篇6相关的知识,希望对你有一定的参考价值。
引言
注意本题与leetcode 46. 全排列----回溯篇5的区别,区别在于本题所给的可选数组中出现了重复数字,并且要求我们返回所有不重复的全排列
回溯法
思路:
可选数组中出现重复数字,那么为什么重复数字会产生重复的全排列呢?
由图中可以看出,因为出现可选数组出现了两个相邻的数字1,因此,当我们选择第二个数字1时,下面的分支是于第一个数字1完全重复的,因此我们需要进行去重操作。
这里去重思路参考三数之和,先对可选数组进行排序,目的是让重复元素相邻,这里我们可以通过if (i > 0 && nums[i] == nums[i - 1]&&!visited[i-1]) continue;来判断是否有重复元素出现
这里i>0是因为当我们选择第一个数字的时候不需要考虑重复问题,并且当i=0时,nums[i-1]会溢出
这里还需要!visited[i-1]是因为重复问题的出现是因为有重复数字,即当我们将第一个重复数字1的所有排列都遍历一遍后,此时我们来对第二个重复数字1进行遍历会得到与前面一个完全一样的排列,因此这条分支要去掉,并且当我们来对第二个重复数字1进行遍历时,第一个重复数字1是处与没有被选择的状态
其实也就是在leetcode 46. 全排列----回溯篇5加上一个去重的操作,其余的操作于46题全排列完全一致
代码:
class Solution {
vector<vector<int>> ret;
vector<int> num;
vector<bool> visited;
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
if (nums.empty()) return ret;
visited.resize(nums.size(), false);
sort(nums.begin(), nums.end());
backTrace(nums);
return ret;
}
void backTrace(vector<int>& nums)
{
if (num.size() == nums.size())
{
ret.push_back(num);
return;
}
for (int i =0; i < nums.size(); i++)
{
if (visited[i]) continue;
// 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
//因为选择第一个数字的时候,不需要考虑重复的问题
// 写 !visited[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
if (i > 0 && nums[i] == nums[i - 1]&&!visited[i-1]) continue;
num.push_back(nums[i]);
visited[i] = true;
backTrace(nums);
num.pop_back();
visited[i] = false;
}
}
};
使用set容器去重
思路:
直接dfs全排列然后使用set暴力去重,即我们只需要将46题中用来存储全排列结果的vector替换成set即可
代码:
class Solution {
set<vector<int>> ret;
vector<int> num;
vector<bool> visited;
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
if (nums.empty()) return vector<vector<int>>();
visited.resize(nums.size(), false);
backTrace(nums);
return vector<vector<int>>(ret.begin(),ret.end());
}
void backTrace(vector<int>& nums)
{
if (num.size() == nums.size())
{
ret.insert(num);
return;
}
for (int i =0; i < nums.size(); i++)
{
if (visited[i]) continue;
num.push_back(nums[i]);
visited[i] = true;
backTrace(nums);
num.pop_back();
visited[i] = false;
}
}
};
总结
对于由重复数字导致的重复结果去重法,有两种思路:
- 参考三数之和的去重思路,先对数组排序,然后使用相邻数字比较,将重复结果的分支去掉
- 使用set容器去重
以上是关于leetcode 47. 全排列 II---回溯篇6的主要内容,如果未能解决你的问题,请参考以下文章