美文网首页
子集 + 子集 II AND 零花钱兑换 + 零钱兑换 II

子集 + 子集 II AND 零花钱兑换 + 零钱兑换 II

作者: 吃掉夏天的怪物 | 来源:发表于2021-07-17 16:28 被阅读0次

78. 子集

方法一 枚举

假设有n个数字,每个数字有出现(1)和不出现(0)两种情况,那么用0和1来表示其子集二进制就是000...000 ~111...111,即0~2^n-1,一共2^n种情况。于是遍历当出现1的时候加入当前表示的子集即可。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        int n = nums.size();
        for(int mask = 0; mask < (1 <<n);mask++){
            vector<int> cur;
            for(int j =0; j < n ;j++){
                if(mask &(1<<j)){
                    cur.push_back(nums[j]);
                }
            }
            res.push_back(cur);
        }
        return res;

    }
};
image.png

方法二 递归

class Solution {
public:
    vector<vector<int>> res;
    vector<int> t;
    int n,i=0 ;
    void dfs(vector<int>& nums,int cur){
        if(cur == n){
            res.push_back(t);
            return ;
        }
        t.push_back(nums[cur]);
        dfs(nums,cur+1);//选择cur这一位
        t.pop_back();
        dfs(nums,cur+1);//没有选这一位
    }
    vector<vector<int>> subsets(vector<int>& nums) {          
        n = nums.size();
        dfs(nums,0);
        return res;
    }
};

90. 子集 II

这道题跟上题不同之处在于,可能包含重复元素。

方法一 递归

在递归时,若发现没有选择上一个数,且当前数字与上一个数相同,则可以跳过当前生成的子集。

class Solution {
public:
    vector<vector<int>> res;
    vector<int> temp;
    int n;
    set<vector<int>> s;
    void dfs(bool choosePre,vector<int>& nums, int cur){
        if(cur == n){
            if(!s.count(temp)){
                res.push_back(temp); 
                s.insert(temp);   
            }
            
            return ;
        }
        dfs(false,nums,cur+1);
        if(!choosePre&& cur >0&&nums[cur-1] == nums[cur]) return;
        temp.push_back(nums[cur]);
        dfs(true,nums,cur+1);
        temp.pop_back();
      
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        n = nums.size();
        sort(nums.begin(),nums.end());
        dfs(false,nums,0);
        return res;
    }
};
image.png

方法二 枚举

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
       vector<vector<int>> res;
        int n = nums.size();
        sort(nums.begin(),nums.end());
       
        for(int mask = 0; mask < (1 <<n);mask++){
            vector<int> cur;
             bool flag = true;
            for(int j =0; j < n ;j++){
                if(mask &(1<<j)){
                    if (j > 0 && (mask >> (j - 1) & 1) == 0 && nums[j] == nums[j - 1]) {
                        flag = false;
                        break;
                    }
                    cur.push_back(nums[j]);
                }
            }
            if(flag){
                res.push_back(cur);
            }
        }
        return res;
    }
};
image.png

扩展

39.组合总和

40. 组合总和 II

46. 全排列

47. 全排列 II

78. 子集

90. 子集 II

322. 零钱兑换

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        m = len(coins)

        dp = [0 for i in range(amount+1)]
        dp[0] = 1
        for i in range(m):
            for j in range(amount, -1, -1):
                if(i == 0 and j % coins[i] == 0):
                    dp[j] = 1
                    continue
                if(j-coins[i]>=0):
                    dp[j] += dp[j-coins[i]]
        return dp[amount]

518. 零钱兑换 II

与零钱兑换不同的是需要考虑重复计算的情况

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int> dp(amount + 1);
        dp[0] = 1;
        for (int& coin : coins) {
            for (int i = coin; i <= amount; i++) {
                dp[i] += dp[i - coin];
            }
        }
        return dp[amount];
    }
};
image.png

相关文章

网友评论

      本文标题:子集 + 子集 II AND 零花钱兑换 + 零钱兑换 II

      本文链接:https://www.haomeiwen.com/subject/herwpltx.html