给定一个可包含重复数字的序列
nums
,按任意顺序 返回所有不重复的全排列。示例 1:
输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]]
- 1
- 2
- 3
- 4
- 5
示例 2:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
- 1
- 2
提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
因为题目不要求返回的排列顺序,因此我们可以对初始化状态排序,将所有相同的元素放在各自相邻的位置,方便之后操作。因此重复元素的存在,我们可以选择元素进行全排列时,可能会存在重复排列
定义一个二维数组ret
用来存放所有可能的排列,一个一维数组path
用来存放每个状态的排列,一个一维数组check
标记元素,然后从第一个位置开始进行递归
一个一维数组check
标记元素,然后从第一个位置开始进行递归
在每个递归的状态中,我们维护一个步数pos
,表示当前已经处理了几个数字
在每个递归状态中,枚举所有下标i
,若这个下标未被标记,并且在它之前的相同元素被标记过,则使用nums
数组中当前下标的元素:
check[i]
标记为1nums[i]
添加至path
数组末尾pos+1
个位置进行递归 check[i]
重新赋值为0,并且删除path
末尾元素表示回溯最后,返回ret
class Solution {
vector path; // 用于存储当前排列的路径
vector> ret; // 用于存储所有满足条件的排列组合
bool check[9]; // 用于记录每个元素是否已经被使用过
public:
vector> permuteUnique(vector& nums) {
sort(nums.begin(), nums.end()); // 对输入数组进行排序,以便后续剪枝操作
dfs(nums, 0); // 调用深度优先搜索函数开始生成排列
return ret; // 返回所有满足条件的排列组合
}
void dfs(vector& nums, int pos) {
if (pos == nums.size()) { // 如果已经遍历完所有元素,说明找到了一个合法的排列
ret.push_back(path); // 将当前排列添加到结果中
return;
}
for (int i = 0; i < nums.size(); i++) {
// 剪枝操作:如果当前元素已经被使用过或者与前一个元素相同且前一个元素未被使用过,则跳过该元素
if (!check[i] && (i == 0 || nums[i] != nums[i - 1] || check[i - 1])) {
path.push_back(nums[i]); // 将当前元素添加到当前排列中
check[i] = true; // 标记当前元素为已使用
dfs(nums, pos + 1); // 继续递归生成下一个元素的排列
path.pop_back(); // 回溯操作:移除当前元素,恢复上一层的状态
check[i] = false; // 标记当前元素为未使用
}
}
}
};