47. Permutations II
关联问题:排列1:46. Permutations, 排列2:47. Permutations II,组合:77. Combinations
问题:给定(存在重复元素)的数组,进行全排列,求出所有排列的可能性。
Example 1: Input: nums = [1,1,2] Output: [[1,1,2], [1,2,1], [2,1,1]] Example 2: Input: nums = [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] Constraints: 1 <= nums.length <= 8 -10 <= nums[i] <= 10
解法:Backtracking(回溯算法)
两个变量:
- 路径path:已经选择好的前几位结果
- 选择列表:当前位置上元素的选择可能性:nums-visited
- visited标记排除已经被选择过的元素。
- nums所有元素。
处理过程:
base:递归退出条件:选择到最后一位结束,这里为已经选择好路径长度==给出的数组长度。
做选择:对于当前位置,选择其中一个可用数字a。
-
- 路径.add(a)
- 选择列表.delete(a)->visited[i]=1
撤销选择:回退到选择数字a之前的状况。
-
- 路径.delete(a)
- 选择列表.add(a)->visited[i]=0
⚠️ 注意:本问题中,允许存在相同的元素,但是在排列中,相同元素在同一位置上的选择,是无效的。
因此,我们需要排除相同元素在同一个位置上的选择。
- 首先对nums进行排列,相同元素则会被连续排列。
- 从第二个重复的元素开始,在同一个位置上的选择:
- 若当前path中该重复的第一个元素已被使用,则当前的排序为全新排列,没有问题。
- 若第一元素没有被使用visited[i-1]==0,则现在选择该重复元素,一定和之前的path选择中该位置使用了第一个元素的排列发生重复,需要跳过。
代码参考:
1 class Solution { 2 public: 3 void traverse(vector<vector<int>>& res, vector<int> nums, vector<int>& path, vector<int>& visited) { 4 if(path.size() == nums.size()) { 5 res.push_back(path); 6 return; 7 } 8 for(int i = 0; i < nums.size(); i++) { 9 if(visited[i]) continue; 10 //该元素nums[i]已被使用在目前的path中,则跳过。 11 if(i!=0 && nums[i]==nums[i-1] && !visited[i-1]) continue; 12 //该元素nums[i],与还没被目前的path中使用的,排在它之前的元素重复, 13 //(说明,上一个path的构造中,在同一个位置,一定已经使用过排在它之前的元素),则跳过。 14 visited[i] = 1; 15 path.push_back(nums[i]); 16 traverse(res, nums, path, visited); 17 path.pop_back(); 18 visited[i] = 0; 19 } 20 return; 21 } 22 vector<vector<int>> permuteUnique(vector<int>& nums) { 23 vector<vector<int>> res; 24 vector<int> path; 25 vector<int> visited(nums.size(), 0); 26 sort(nums.begin(), nums.end()); 27 traverse(res, nums, path, visited); 28 return res; 29 } 30 };
另,swap方法:
参考:leetcode说明
swap不需要恢复位置。与递归调用中重复元素的排除有关。
代码参考:
1 class Solution { 2 public: 3 void traverse(vector<vector<int>>& res, vector<int> nums, int pos) { 4 if(pos == nums.size()) { 5 res.push_back(nums); 6 return; 7 } 8 for(int i = pos; i < nums.size(); i++) { 9 if(i!=pos && nums[i]==nums[pos]) continue; 10 swap(nums[i], nums[pos]); 11 traverse(res, nums, pos+1); 12 } 13 return; 14 } 15 vector<vector<int>> permuteUnique(vector<int>& nums) { 16 vector<vector<int>> res; 17 sort(nums.begin(), nums.end()); 18 traverse(res, nums, 0); 19 return res; 20 } 21 };