leetcode-47-Permutations II 搜索-剪枝

问题

题目:[Permutations II]

思路

上来下来个简单的办法,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);
                        }

                  }


              }    
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值