Permutations II
Given a list of numbers with duplicate number in it. Find all unique permutations.
http://www.lintcode.com/en/problem/permutations-ii/
Discussion
有重复元素的排列问题。
最简单的办法是对Permutation的结果去重就可以了。结果去重的问题在3 Sum问题里也遇到过了。对Permutation的结果进行去重操作:
sort(result.begin(), result.end());
vector<vector<int> >::iterator it = unique(result.begin(), result.end());
result.resize(it-result.begin());//or result.erase(it, result.end());
当然这样会有重复计算问题,虽然没有增加时间复杂度。更好的办法是修改backtracing算法,或者是修改递归终止条件:只有在跟上一个solution不同的时候才会把新的solution记录下来,这样做每次都要比较n次,而产生solution的操作并没有受到影响,所以还是会重复计算;
或者是修改backtracing终点的第二部分:在每一维上枚举candidate number的时候,该number不但不能被枚举过, 而且还要跟上次出现在该维度上的number不同。比如“1 1 2”,solution[0]为1的时候下一个1就不用再放到第0维上了。
Solution
class Solution {
public:
/**
* @param nums: A list of integers.
* @return: A list of unique permutations.
*/
vector<vector<int> > permuteUnique(vector<int> &nums) {
// write your code here
vector<vector<int> > result;
int n = nums.size();
if(n == 0) return result;
vector<int> solution(n, 0);
vector<bool> used(n, false);
sort(nums.begin(), nums.end());
backtracing(nums, 0, result, solution, used);
return result;
}
private:
void backtracing(vector<int> &nums, int dim, vector<vector<int> > &records,
vector<int> &solution, vector<bool> &used) {
int n = nums.size();
if(dim == n) {
records.push_back(solution);
return;
}
int lastnum = INT_MAX;
for(int i = 0; i<n; i++) {
if(used[i] == true) continue;
if(nums[i] == lastnum) continue;//修改枚举条件,跟上次不同的时候才会记录到solution里
lastnum = nums[i];
solution[dim] = nums[i];
used[i] = true;
backtracing(nums, dim+1, records, solution, used);
used[i] = false;
}
}
};
起始lastnum初始化为INT_MAX是有问题的,test case没有测出来。应该初始化为num[0]-1;这样就能保证lastnum一开始跟任意个都不同了(已经排序)。
DFS solution. 改造Subsets II问题模板。
class Solution {
public:
/**
* @param nums: A list of integers.
* @return: A list of unique permutations.
*/
vector<vector<int> > permuteUnique(vector<int> &nums) {
// write your code here
vector<vector<int> > result;
if(nums.empty()) return result;
vector<int> path;
vector<int> state(nums.size(), false);
sort(nums.begin(), nums.end());
dfs(nums, result, path, state);
return result;
}
void dfs(vector<int> &nums, vector<vector<int> > &records,
vector<int> &path, vector<int> &state) {
int n = nums.size();
if(path.size() == n) {
records.push_back(path);
return;
}
for(int i=0; i<n; i++) {
if(state[i] == true) continue;
if(i!=0 && nums[i] == nums[i-1] && state[i-1]==false) continue;
//这里刚开始漏掉了state[i-1]==false
state[i] = true;
path.push_back(nums[i]);
dfs(nums, records, path, state);
path.pop_back();
state[i] = false;
}
}
};
Solution 3
基于交换。去重有技巧。
num[i] == num[pos]
- 是跟pos去比,因为这决定了还要不要swap- 不能引用传递num,然后两次swap,这样的num再到下一层的时候总是有序的,这样就没法去重了。
- https://leetcode.com/discuss/25279/a-simple-c-solution-in-only-20-lines
class Solution {
public:
void recursion(vector<int> num, int pos, vector<vector<int> > &res) {
if (pos == num.size()) {
res.push_back(num);
return;
}
for (int i = pos; i < num.size(); i++) {
if (i != pos && num[i] == num[pos]) continue;
swap(num[i], num[pos]);//这里的swap只影响当前recursion,因为num不是引用传递
recursion(num, pos+1, res);
}
}
vector<vector<int> > permuteUnique(vector<int> &num) {
sort(num.begin(), num.end());
vector<vector<int> >res;
recursion(num, 0, res);
return res;
}
};