问题
思路
上来下来个简单的办法,STL套路。
代码
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
std::vector< std::vector<int> > ret;
std::sort( nums.begin(), nums.end() );
do ret.push_back( nums );
while( std::next_permutation( nums.begin(), nums.end() ) );
return ret;
}
};
思路
当然,利用上一题的做法,上来就对位置全排列。每一次到边界的时候放到集合里面去,去重。思路完全可行。但是没有考虑复杂度,因为位置全排列,长度为n的数组,按位置全排列时n!,这个复杂度非常不可接受。上一道能过是因为,就是那么多,所以好的办法。但是这个题目应该存在明显的剪纸的情形可以优化复杂度。
代码1(TLE)
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
std::set< std::vector<int> > ret;
std::vector< int > arr( nums.size(), int() );
std::set<int> visit;
dfs( 0, arr, visit, nums, ret );
std::vector< std::vector<int> > ret1(ret.begin(), ret.end() );
return ret1;
}
private:
void dfs( int depth, std::vector<int>& arr, std::set<int>& visit,
const std::vector<int>& nums, std::set< std::vector<int> >& ret ){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::set<int> __visit = visit;
if( __visit.find( i ) == __visit.end() )
{
arr[depth] = nums[i];
__visit.insert( i ); // insert the location of nums[i]
if( sz-1 == depth )
ret.insert( arr );
else
dfs( depth+1, arr, __visit, nums, ret );
}
}
}
};
思路
前面已经说了,上来位置全排列。但是不行,dfs复杂度太大。所以,剪枝。剪枝有两个点需要考虑。
- 如果同一层次,当前试探元素前面有重复元素,需要剪枝。[1,1,2],因为同一层次如果元素相同,考虑互相交换后的结果,试探的分枝一样。所以,剪枝。
- 在上面基础之上,剪枝时需要小心一点,如果前面的元素已经出现在上一个层次当中,比如对于第二层的元素,应该在本层的有效元素当中,考虑对重复元素的剪枝。比如[1,1,2],第一层用1展开,第二层,如果只是考虑前面元素是否重复,那么第二个1无法展开,但是第一个1已经出现在上一个层次当中,所以应该避免考虑这些元素。
最后说一个,昨天位置全排列需要小心的一点就是,每层所有元素试探的时候,本质是相互独立的,所以均要使用上一层次的哈希表。
考虑[1,1,1],第一层试探1,第二层试探第二个1,虽然前面出现了1,但是由于第一个1在上一个层次,所以不影响。第二个1展开。还是对于第二层,第三个1,由于第二个1没有在上一层出现过,并且和当前1重复,所以当前试探剪枝。
代码2(剪枝)
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
int sz = nums.size();
std::vector< std::vector<int> > ret;
std::vector< int > arr( sz, int() );
std::set<int> visit;
dfs( 0, arr, visit, nums, ret);
return ret;
}
private:
void dfs( int depth, std::vector<int>& arr, std::set<int>& visit,
const std::vector<int>& nums, std::vector< std::vector<int> >& ret){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::set<int> __visit = visit;
int j;
for( j = 0; j < i; ++j )
{
if( __visit.find(j) != __visit.end() ) // j 在上一层出现过,不影响本层的重复
continue;
if( nums[j] == nums[i] )
break;
}
if( j < i )
continue;
if( __visit.find( i ) == __visit.end() )
{
arr[depth] = nums[i];
__visit.insert( i ); // insert the location of nums[i]
if( sz-1 == depth )
ret.push_back( arr );
else
dfs( depth+1, arr, __visit, nums, ret);
}
}
}
};