Leetcode 47. Permutations II
2017-01-28 09:13
127 查看
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
s思路:
1. 方法1,用backtracking,和之前的一道题一样,除了需要先排序,方便通过比较前后两个数是否相等。需要怎么检测重复呢
2. 为找到判断条件,需要理解backtracking的精神实质:backtracking = for+recursive。recursive是处理不同层次的数,即:纵向的深度的方向的遍历,即:不同的位置坐标;for是用在同一个层次的数,即:横向的遍历,即:同一个位置上尝试不同的数。
例如:[1,1,1,2,2,3], recursive是位置坐标从0-5的遍历,每一个位置代表一个层次,在每一个层次(位置)上,有多种可能的选择。
3. 为找到重复的组合,如果在同一个层次(位置)上,已经选用过某一个数,那么在同一个位置上再碰到这个数,就需要skip,因为在第一次遇到这个数的时候已经尝试了所有可能的组合。所以,
即:nums[i-1]==nums[i]表示数据一样,!used[i-1]表示i-1这个数是这个层次遍历后复位为0的位置,也就是说,i-1一定是这个层次先遍历的一种可能,同一个层次尝试nums[i-1]之后,需要复位对应的标志位,才进入同一个层次下一个位置nums[i];如果used[i-1]==1,则说明i-1这个位置是之前某个层次(位置)正在遍历并置位为1,和当前不是一个层次,这种情况下,就不能skip。
方法2:
1. 用交换的方法,为了判断重复,序列要先排序。但是,交换元素又会破坏数据的sorting的性质。因此,交换和sorting对同一个序列操作,必然导致不好处理的情况,或者说交换是适合没有重复元素的序列做permutation的,其对含有重复元素序列并不理想。
2. 不过网上还是有一种比较简洁的方法用交换+sorting:举例:
注意看:和普通的交换不同,每次交换后,不用交换回来,这样就可以保证sorting+交换的compatibility.上面例子就是: 1和2交换后,2就放在第一个位置了,同一个层次的遍历后面数据是,直接用2和3交换。
方法3:
1. 用map来做,把数存在vector,相同的数还是分散的,可以用map把相同的数放在一起,这样就不担心重复了!而且实际中,都没有必要使用map,用unordered_map就足够了!
2. 这个例子也说明了,数据结构对解题的思路的帮助!用map把相同数放在一起,现在map就相当没有重复元素的vector了。以后处理重复元素,就多了一个思路:把相同元素group起来!
For example,
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
s思路:
1. 方法1,用backtracking,和之前的一道题一样,除了需要先排序,方便通过比较前后两个数是否相等。需要怎么检测重复呢
2. 为找到判断条件,需要理解backtracking的精神实质:backtracking = for+recursive。recursive是处理不同层次的数,即:纵向的深度的方向的遍历,即:不同的位置坐标;for是用在同一个层次的数,即:横向的遍历,即:同一个位置上尝试不同的数。
例如:[1,1,1,2,2,3], recursive是位置坐标从0-5的遍历,每一个位置代表一个层次,在每一个层次(位置)上,有多种可能的选择。
3. 为找到重复的组合,如果在同一个层次(位置)上,已经选用过某一个数,那么在同一个位置上再碰到这个数,就需要skip,因为在第一次遇到这个数的时候已经尝试了所有可能的组合。所以,
i>0&&nums[i-1]==nums[i]&&!used[i-1]
即:nums[i-1]==nums[i]表示数据一样,!used[i-1]表示i-1这个数是这个层次遍历后复位为0的位置,也就是说,i-1一定是这个层次先遍历的一种可能,同一个层次尝试nums[i-1]之后,需要复位对应的标志位,才进入同一个层次下一个位置nums[i];如果used[i-1]==1,则说明i-1这个位置是之前某个层次(位置)正在遍历并置位为1,和当前不是一个层次,这种情况下,就不能skip。
//方法1:到底叫backtracking,还是DFS? class Solution { public: void helper(vector<vector<int>>&res,vector<int>& nums,vector<int> cur,vector<bool>&used,int pos){ if(pos==nums.size()){ res.push_back(cur); return; } for(int i=0;i<nums.size();i++){ if(used[i]||i>0&&nums[i-1]==nums[i]&&!used[i-1]) continue;//需要解释下!! cur.push_back(nums[i]); used[i]=1; helper(res,nums,cur,used,pos+1); used[i]=0; cur.pop_back(); } } vector<vector<int> > permuteUnique(vector<int> &num) { // sort(nums.begin(),nums.end()); vector<vector<int>> res; vector<bool> used(nums.size(),0); helper(res,nums,{},used,0); return res; } };
方法2:
1. 用交换的方法,为了判断重复,序列要先排序。但是,交换元素又会破坏数据的sorting的性质。因此,交换和sorting对同一个序列操作,必然导致不好处理的情况,或者说交换是适合没有重复元素的序列做permutation的,其对含有重复元素序列并不理想。
2. 不过网上还是有一种比较简洁的方法用交换+sorting:举例:
P[1,1,1,2,2,2,3,3]= {[1]+P[1,1,2,2,2,3,3]}+ {[2]+P[1,1,1,2,2,3,3]}+ {[3]+P[1,1,1,2,2,2,3]}
注意看:和普通的交换不同,每次交换后,不用交换回来,这样就可以保证sorting+交换的compatibility.上面例子就是: 1和2交换后,2就放在第一个位置了,同一个层次的遍历后面数据是,直接用2和3交换。
//方法2:交换位置+backtracking:代码短,省空间,速度快! class Solution { public: void helper(vector<vector<int>>&res,vector<int> nums,int start){ if(start==nums.size()){ res.push_back(nums); return; } for(int i=start;i<nums.size();i++){ if(i!=start&&nums[start]==nums[i]) continue; swap(nums[start],nums[i]); helper(res,nums,start+1); } } vector<vector<int> > permuteUnique(vector<int> &nums) { sort(nums.begin(),nums.end()); vector<vector<int>> res; helper(res,nums,0); return res; } };
方法3:
1. 用map来做,把数存在vector,相同的数还是分散的,可以用map把相同的数放在一起,这样就不担心重复了!而且实际中,都没有必要使用map,用unordered_map就足够了!
2. 这个例子也说明了,数据结构对解题的思路的帮助!用map把相同数放在一起,现在map就相当没有重复元素的vector了。以后处理重复元素,就多了一个思路:把相同元素group起来!
//方法3:map class Solution { public: vector<vector<int> > permuteUnique(vector<int> &num) { unordered_map<int,int> mm; for (int i : num) { mm[i]++; } vector<vector<int>> res; vector<int> cur; helper(res,mm,cur,num.size()); return res; } void helper(vector<vector<int>>&res,unordered_map<int,int>&mm,vector<int>&cur,int count){ if(count==0){ res.push_back(cur); return; } for(auto&p:mm){//超级大bug:写成auto p:mm就不能修改mm的值, //要修改mm的值,就一定要用auto&p:mm if(p.second==0) continue; p.second--; cur.push_back(p.first); helper(res,mm,cur,count-1); cur.pop_back(); p.second++; } //不用上面的简洁形式,就只有下面笨重的iterator了。 /*for(auto p=mm.begin();p!=mm.end();p++){ if(p->second==0) continue; p->second--; cur.push_back(p->first); helper(res,mm,cur,count-1); cur.pop_back(); p->second++; }*/ } };
相关文章推荐
- android Google Map获取地理位置信息的方法
- Spark RDD API详解(一) Map和Reduce
- Python中map()函数浅析
- Android使用Google Map浅谈
- BackTrack平台中主流渗透测试工具
- Erlang中的映射组Map详细介绍
- c++中map的基本用法和嵌套用法实例分析
- C++中vector和map的删除方法(推荐)
- 浅谈c++中的stl中的map用法详解
- 微信小程序 地图map详解及简单实例
- 一个简单的JavaScript Map实例(分享)
- 百度地图给map添加右键菜单(判断是否为marker)
- JavaScript中实现Map的示例代码
- js遍历map javaScript遍历map的简单实现
- jquery中map函数与each函数的区别实例介绍
- jQuery 遍历map()方法详解
- jquery中map函数遍历数组用法实例
- jquery与google map api结合使用 控件,监听器
- 浅谈jquery的map()和each()方法
- Jquery中map函数的用法