这个题是对上一个题的变形,变化的条件是数组里面可以出现相同的元素,这样确实加大了难度。不过在上个题的基础上我们可以把精力主要放在怎么处理重复的数字。如果没有记错,我们之前的一道题也是类似情况,我看了一下是 LeetCode 40 ,那个题是nsum问题,这里我们还是可以借鉴那种思想去处理重复的数字,我们还是用 prev 变量来保存已经使用过的值,下次遇到相同的值的时候我们就可以直接跳过,利用这样的方法来过滤掉重复的情况。思想和上个题大致相同,所以我就不再详细说明了。
代码:
class Solution {
public:vector<vector<int>> permuteUnique(vector<int>& nums) {vector<vector<int>> ret;ret.clear();if (nums.size() == 0){}else if (nums.size() == 1){vector<int> tmp;tmp.push_back(nums[0]);ret.push_back(tmp);}else{// 排序数组,便于过滤重复数字sort(nums.begin(), nums.end());// 数组的元素的个数满足递归要求,进行递归求解solves(ret, nums, 0);}return ret;}void solves(vector<vector<int>>& ret, vector<int> nums, int index){if (index > nums.size()){return;}else if (index +1 == nums.size()){vector<int> tmp;for (int i = 0; i < nums.size(); ++i){ // 该情况符合,保存到vector中tmp.push_back(nums[i]);}ret.push_back(tmp);return;}int begin = index;int prev = 0; //保存递归出来的值,用于过滤重复值for (int i = index; i < nums.size(); ++i){if (i != begin){if (nums[i] == nums[begin] || nums[i] == prev){continue;}swap(nums[begin], nums[i]);}solves(ret, nums, index + 1);prev = nums[i];}}
};
最后我总结一下这种全排列问题的解法吧:
1. 使用递归求解,这是很容易理解的,这种题使用循环的话就会变得很冗余。
2. 这种题的思想都是将整个问题分为两个部分,就这个题来说吧:题目给定一个数组,我们每层递归都是从现有数字中取出一个,然后将剩下的作为一个整体进行求解,最终规模只剩 1 的时候就可以求出解了。然后递归出来后,将之前取出的数字依次和剩下序列中的数字进行交换然后递归,这样就会考虑到所有情况,而且也比较容易理解。
3.遇到有重复数字出现的情况,先将数组排序,这样有利于处理掉重复数字,重复数字的处理方法是利用一个 prev 变量保存递归返回时”取出的数字“,然后下次遇到和prev 相同的数字的时候就过滤掉(continue),这样重复数字就被处理掉了(这一点如果不理解就看看代码中 prev 是怎么使用的,然后再来看看这一点)