题目描述
解法
这道题同样还是回溯剪枝的问题,但是这里的剪枝有点技巧。我们先来分析一下,例如, n u m s = [ 1 , 2 , 2 ′ ] nums = [1,2,2'] nums=[1,2,2′],不剪枝的话,会得到如下的结果
[
[1,2,2'],[1,2',2],
[2,1,2'],[2,2',1],
[2',1,2],[2',2,1]
]
如果我们保证相同元素在排列中的相对位置保持不变,比如说 n u m s = [ 1 , 2 , 2 ′ ] nums = [1,2,2'] nums=[1,2,2′] 这个例子,我保持排列中 2 2 2 一直在 2 ′ 2' 2′ 前面。这样的话,你从上面 6 个排列中只能挑出 3 个排列符合这个条件:
[
[1,2,2'],[2,1,2'],[2,2',1]
]
仔细思考,应该很容易明白其中的原理:
标准全排列算法之所以出现重复,是因为把相同元素形成的排列序列视为不同的序列,但实际上它们应该是相同的;而如果固定相同元素形成的序列顺序,当然就避免了重复
那么反映到代码上,你注意看这个剪枝逻辑:
// 新添加的剪枝逻辑,固定相同的元素在排列中的相对位置
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
// 如果前面的相邻相等元素没有用过,则跳过
continue;
}
// 选择 nums[i]
完整实现如下
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<int> track;
vector<int> used(nums.size(), 0);
sort(nums.begin(), nums.end());
backtrace(nums, track, used);
return res;
}
void backtrace(vector<int>& nums, vector<int>& track, vector<int>& used)
{
if (track.size() == nums.size())
{
res.push_back(track);
return;
}
for (int i = 0; i < nums.size(); i++)
{
if (used[i]) continue;
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0) continue;
track.push_back(nums[i]);
used[i] = 1;
backtrace(nums, track, used);
used[i] = 0;
track.pop_back();
}
}
};