LintCode-17: Subset 和 Subset II (搜索题中的超级经典!)

SubSet 这题有4种解法,其中DFS两种,BFS一种,位运算一种。
解法1:
DFS 通用回溯解法。
注意:
1) 是每次进入helper()的sol都是一个解,所以不用等到index=nums.size()再存到results里面。
2) vector < vector < int> > results;
results的值会是[]。如果想让它变成[[]],要用results.push_back(vector());

class Solution {
public:
    /**
     * @param nums: A set of numbers
     * @return: A list of lists
     */
    vector<vector<int>> subsets(vector<int> &nums) {
        vector<vector<int> > results;
        vector<int> sol;

        if (nums.empty()) {
          results.push_back(vector<int>());
          return results;
        }

        sort(nums.begin(), nums.end());

        helper(nums, 0, sol, results);
        return results;
    }

    void helper(vector<int> &nums, int index, vector<int>&sol, vector<vector<int>> &results) {

        results.push_back(sol);
        for (int i=index; i<nums.size(); ++i) {
            sol.push_back(nums[i]);
            helper(nums, i+1, sol, results);
            sol.pop_back();
        }
    }

};

解法4:位运算

    vector<vector<int>> subsets(vector<int> &nums) {
        vector<vector<int> > solution;
        vector<int> singleSol;
        int numSize=nums.size();
        int totalNum=pow(2,numSize)-1;
        solution.push_back(singleSol);

        for (int i=1; i<=totalNum; ++i) {
            singleSol.clear();
            for(int j=0; j<numSize; ++j) {
                int bitNum = (i>>j)&0x1;
                if (bitNum==1) {
                    singleSol.push_back(nums[j]);
                }
                sort(singleSol.begin(), singleSol.end());
            }

            solution.push_back(singleSol);
        }
        return solution;
    }

效率可能还要改进一下。

另外2种下次写。

另外分析一下算法复杂度。关于DFS的时间复杂度是O(答案个数×构造每个答案时间)。所以以上DFS的时间复杂度都是O(n*2^n)。

SubSet II 和SubSet类似,但是要注意去重。
以通用回溯解法为例:

   vector<vector<int>> subsetsWithDup(vector<int> &nums) {
        vector<vector<int>> results;
        vector<int> sol;

        if (nums.empty()) {
            results.push_back(vector<int>());
            return results;
        }

        sort(nums.begin(), nums.end());    
        helper(nums, 0, sol, results);
        return results;
    }

    void helper(vector<int>&nums, int index, vector<int>&sol, vector<vector<int>>&results) {
        results.push_back(sol);
        for (int i=index; i<nums.size(); ++i) {
            if ((i!=index) && (nums[i-1]==nums[i]))  //去重
                continue;
            sol.push_back(nums[i]);
            helper(nums, i+1, sol, results);
            sol.pop_back();
        }
    }

为啥这个可以去重呢? 以[1,2,2]为例,

这里写图片描述

      if ((i!=index) && (nums[i-1]==nums[i]))  //去重
                continue;

参考上面的代码,
第2行,取到[2]之后,就不会取第2个2了。
第3行,取到[1,2]之后,不会再取下一个[1,2]。同时它继续调用helper(,index+1,) 这里index+1=2,所以进helper()之后,index=2, i=2==index(第一次),所以第4行还是会有[1,2,2]。

同样,回溯到[2]之后会继续调用helper(,index+1,)。这里index+1=2。所以第3行还是会有[2,2],因为i==index。

猜你喜欢

转载自blog.csdn.net/roufoo/article/details/80761990
今日推荐