力扣47. 全排列 II
思路
用 used 保存在一次答案中取过的数组索引。
先对数组进行排序,然后尝试取每个元素作为排列。
- 首先需要满足不重复取自己,即
!used.contains(i)
。 - 其次当前元素和前一个元素不同时可取,即
i == 0 || nums[i] != nums[i - 1]
;- 如果当前元素和前一个元素相等,且它前面的元素没取过,则说明重复了。
换句话说,如果取到了当前元素,但它前面的元素没取过,就说明现在是没按顺序取的。在这俩相等的情况下(因为如果不等前面
nums[i] != nums[i - 1]
就判断可取了),之前一定按顺序取过一次,所以一定重复了。
对于最后一种难懂的情况,例如 nums = [1, 1', 2]
(记第二个1为1’),顺序时按照 1, 1', 2
的顺序取过一次答案了,因此在以 1’ 作为第一个元素时,就不能再取一次 1', 1, 2
作为答案了(此时 i == 1, used.contains(i - 1) == False
)。
代码
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
vector<int> nums;
unordered_set<int> used; // 用于保存取过的nums索引
void backTrack() {
if (path.size() == nums.size()) {
result.emplace_back(path);
}
else {
for (int i = 0; i < nums.size(); i++) {
if (!used.contains(i) && (i == 0 || nums[i] != nums[i - 1] || used.contains(i - 1))) {
path.emplace_back(nums[i]);
used.insert(i);
backTrack();
path.pop_back();
used.erase(i);
}
}
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
this->nums = nums;
backTrack();
return result;
}
};