leetcode:47. 全排列 II - 力扣(LeetCode)
题目
给定一个可包含重复数字的序列 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
思路
跟上一题的区别在于nums里面有重复的元素,那么同一树层上的元素不可以重复取,同一树枝上的元素(实际是元素值相等的不同元素)可以重复取,这就是used数组的正常情况了,那这里跟组合/子集的区别就是startIndex了,排列不需要startIndex!
前面的题目做熟了,我就直接写代码了:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
private:
vector<vector<int>> result;
vector<int> path;
/**
* @brief 使用回溯法生成给定数组的所有排列
*
* 本函数通过回溯法生成给定数组nums的所有排列。为了避免重复生成相同的排列,
* 使用了一个布尔数组used来标记数组中的元素是否已经被使用。当path的大小与nums相等时,
* 表示已经生成了一个完整的排列,将其添加到结果集result中。
*
* @param nums 输入的整数数组
* @param used 布尔数组,用于标记nums中的元素是否被使用
*/
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 (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)
{
continue;
}
// 当前元素未被使用时,将其添加到当前排列中
if (used[i] == false)
{
used[i] = true; // 标记当前元素为已使用
path.push_back(nums[i]); // 将当前元素添加到排列中
backtracking(nums, used); // 递归生成排列
path.pop_back(); // 回溯,移除最后一个元素
used[i] = false; // 标记当前元素为未使用
}
}
}
public:
vector<vector<int>> permuteUnique(vector<int> &nums)
{
result.clear();
path.clear();
vector<bool> used(nums.size(), false);
sort(nums.begin(), nums.end());
backtracking(nums, used);
return result;
}
};
总结
这道题每次都错在:
// 当前元素未被使用时,将其添加到当前排列中
if (used[i] == false)
{
used[i] = true; // 标记当前元素为已使用
path.push_back(nums[i]); // 将当前元素添加到排列中
backtracking(nums, used); // 递归生成排列
path.pop_back(); // 回溯,移除最后一个元素
used[i] = false; // 标记当前元素为未使用
}
因为在上道题里面nums没有重复的,所以就没有加if(used[i]==false)这个判断条件,这道题如果不加的话,树枝的元素一直被重复使用了