leetcode#47 全排列II
题目:
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
思路:
1、用标记数组vis,标记数组vis标记最好位置用没用过,因为你要标记数用没用过,不能用true or false,得用个数来描述还有多少个可用,其次如果数组里面的数很大,比如1e9,你就不能开vis[1e9]的数组了,需要离散化,比较麻烦,所以我们vis来标记位置。
2、考虑这个例子,你就明白了
2 1 1 2
第一种:
2 1 1 2
| | | |
2 1 1 2
第一个选2,第二个选第一个1,第三个选第二个1,第三个选第二个2.
第二种:
2 1 1 2
| X |
2 1 1 1
第一个选2,第二个选第二个1,第三个选第一个1,第四个选第二个2.
我们发现两个一样的排列,区别是第二种中,我们没有选择第一个1,而选择了第二个1,效果是一样的,因为我们vis标记的是位置,导致两个1不同,但选出来的结果一样的。
对于当前要填写的位置,原先是,要么选第一个1,要么选第二个1不管选哪个选出来都是1,这样是不对的,我们,把所有1看成一个整体,我们改成要么选1,要么就不选了,也就是第一个1如果不选后面的1不选了。
因此加上一个下面的判断条件就可以了。
if (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])
continue;
要让相等的数相邻才能判断,这也是我们排序的原因。
代码:
class Solution
{
public:
int len;
vector<bool> vis;
vector<vector<int>> ans;
vector<int> tmp;
void dfs(int step, vector<int> &nums)
{
if (step == len)
{
ans.push_back(tmp);
return;
}
for (int i = 0; i < len; ++i)
{
if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1]))
continue;
vis[i] = true;
tmp.push_back(nums[i]);
dfs(step + 1, nums);
tmp.pop_back();
vis[i] = false;
}
}
vector<vector<int>> permuteUnique(vector<int> &nums)
{
len = nums.size();
sort(nums.begin(), nums.end());
vis.resize(nums.size());
dfs(0, nums);
return ans;
}
};