1. 回溯
类似的题目是46.全排列,数组中不包含可重复数字,所以直接对于每一位遍历每一个,选择然后回溯不选择。
而这道题目的数组中包含重复数字,因此如果按照上述方法,会出现重复排列。
如:  
1 2 3 4 5 6
   |    /   |   \     1    1    2      位置1   /\   /\    /\   1  2  1 2   1 1    位置2   |  |  | |   | |   2  1  2 1   1 1    位置3  
   | 
 
出现重复排列的原因是,对于当前位置,已经选择过的数字在之后又被重新选择了(但选择的不是同一个元素,只是它们的值相等)
因此避免重复的方法就是,在当前位置,避免选择之前已经选择过的数字。  
想象在当前位置,第一次选择某个数字,则这个数字一定是所有相等的数字中,第一个在数组中未被选择的,选择它并置vis为true。
在获得当前位置为这个数字得到的所有排列之后,当前位置的数字被重新选择,并将之前元素的vis置为false。
如果选择到的元素还是相等的数字,则之后的排列一定是已经获得过的,并且可以发现它不是数组的相等数字中第一个未被选择的。
因此算法是,先将数组排序,将相等的元素放在一起,然后dfs,选择元素时只选择前一个相等元素被选择过的。
时间O(n*n!),空间O(n)。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
   | class Solution { public:     vector<vector<int>> permuteUnique(vector<int>& nums) {         int n = nums.size();         if (n == 0)             return {};
          vector<bool> vis(n, false);         vector<int> subAns;         vector<vector<int>> ans;
          sort(nums.begin(), nums.end());         dfs(nums, vis, subAns, ans);
          return ans;     } private:     void dfs(vector<int>& nums, vector<bool>& vis, vector<int>& subAns, vector<vector<int>>& ans) {         int n = nums.size();         if (subAns.size() == n) {             ans.push_back(subAns);             return;         }
          for (int i = 0; i < n; i++) {             if (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])                 continue;             if (!vis[i]) {                 subAns.push_back(nums[i]);                 vis[i] = true;                 dfs(nums, vis, subAns, ans);                 subAns.pop_back();                 vis[i] = false;             }         }     } };
  |