LeetCode题解 动态规划(五):494 目标和;474 一和零

494 目标和

给你一个整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 ‘+’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

这道题摆明了是可以用回溯来做的。后面给出相应的代码

那么如果要用动规来计算,就涉及到一些数学相关的内容。设数组总和为sum,符号为正的数字之和为pos,符号为负的数字之和为neg,则有(sum - neg) - neg = target,即neg = (sum - target)/2,这是必须要满足的条件。

随想录中使用正数之和pos = (sum + target)/2,也是可以的。

上面的正数之和就是背包大小,我们的目标就是试图找到正数之和为pos的数字组合数,根据这一思想,代码如下:

int findTargetSumWays(vector<int>& nums, int target) {
    
    
    int sum = 0;
    for (int num: nums) sum += num;
    if (abs(target) > sum) return 0;
    if ((sum + target) % 2 == 1) return 0;

    int bagSize = (sum + target) / 2;
    vector<int> dp(bagSize + 1, 0);
    dp[0] = 1;
    for (int i = 0; i < nums.size(); ++i) {
    
    
        for (int j = bagSize; j >= nums[i]; --j) {
    
    
            dp[j] += dp[j - nums[i]];
        }
    } 
    return dp[bagSize];
}

回溯即可以按照目标值为pos,也可以直接处理,此处按照后面的思想给出代码:

int cnt = 0;
void reback(vector<int>& nums, int target, int sum, int index) {
    
    
    // 终止条件
    if (index == nums.size()) {
    
    
        if (sum == target) cnt++;
    }else {
    
    
        reback(nums, target, sum + nums[index], index + 1);
        reback(nums, target, sum - nums[index], index + 1);
    }
}

int findTargetSumWays(vector<int>& nums, int target) {
    
    
    reback(nums, target, 0, 0);

    return cnt;
}

474 一和零

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

做这道题要明确,零和一的个数,是用于限定子集中所有零和一的总数的,比如

示例 2:

输入:strs = ["10", "0", "1"], m = 1, n = 1
输出:2
解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

所以要定义一个由两个变量控制的二维数组

dp[i] [j]表示只能放入i个0,j个1时,最大子集的大小

要能把一个字符串放入子集中,该字符串零和一的个数都需要满足条件,

dp[i] [j] = max(dp[i] [j], dp[i - zeroNum] [j - oneNum] + 1)

而且,要考虑每个字符只能放一个,所以就得从数组的右下角开始,往左上方向走,相当于,剩下还有多少个0和1能放,而不是一定要塞满0和1的总数,这也是这道题变通的地方。

根据上述思想,代码如下:

int findMaxForm(vector<string>& strs, int m, int n) {
    
    
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    for (string str : strs) {
    
    
        int oneNum = 0, zeroNum = 0;
        for (char c : str) {
    
    
            if (c == '0') zeroNum++;
            else oneNum++;
        }
        for (int i = m; i >= zeroNum; i--) {
    
    
            for (int j = n; j>= oneNum; j--) {
    
    
                dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
            }
        }
    }

    return dp[m][n];
}

猜你喜欢

转载自blog.csdn.net/qq_41205665/article/details/128992318