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]]
解题思路:
排列 + 去重
问 答 如何去重? 分两步走,详细见下文. 递归返回条件 如果路径长度等于数组长度,就说明找到一种结果.添加并放回 单层递归 从0开始遍历整个数组,如果已经遍历过或者是重复的就跳过这一个,寻找满足条件的递归 参数 需要一个标记数组来记录是否已经用过 剪枝 不需要 遇到这种需要不重复的,我们需要的就是在原来递归的基础上做多两步.
- 排序数组,让相同的数字相邻
- 如果在同一层中的非首位数等于后面的数且后面的数等于false(说明已经递归过一个相同的数了),就不继续遍历这个数
代码
class Solution {
public:
//递归回溯
//num是原数组,used是标记位
void backtracking(vector<int> &nums,vector<bool>& used)
{
//如果长度和nums长度一样,说明找到一种可能
if (path.size() == nums.size())
{
res.push_back(path);
return;
}
//从0开始遍历整个数组
for (int i = 0; i < nums.size(); i++)
{
//如果当前位已经在路径中,不需要继续递归,直接跳过
if (used[i] == true)
continue;
//如果不是第一位 && 与后面一位相等 && 后面一位已经被作为起始点被递归过了. 就直接跳过.防止重复
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)
continue;
//添加当前值到路径中
path.push_back(nums[i]);
//标记当前位
used[i] = true;
//递归寻找下一位
backtracking(nums, used);
//回溯
used[i] = false;
path.pop_back();
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
//先排序
sort(nums.begin(), nums.end());
//创建一个标记数组
vector<bool> flag(nums.size(), false);
//开始递归
backtracking(nums, flag);
return res;
}
private:
vector<vector<int>> res;
vector<int>path;
};
总结:
在排序的基础上加上一个去重即可.去重比较巧妙,用到了标记数组.需要想清楚其中的逻辑