代码随想录第四十三天——目标和,一和零

leetcode 494. 目标和

题目链接:目标和

本题要如何使表达式结果为target:

既然为target,那么就一定有 left组合 - right组合 = target

left + right = sum,而sum是固定的。right = sum - left,所以left - (sum - left) = target 推导出 left = (target + sum)/2 。

此时问题就转化为:装满容量为left的背包,有几种方法

本题是求解装满一个背包有几种方法,属于组合问题,与之前的背包问题不同。

  1. 确定dp数组以及下标的含义
    dp[j] :填满j(包括j)这么大容积的包,有dpj种方法
  2. 确定递推公式
    以dpj,j 为5为例:
    已经有1(numsi)的话,有 dp4种方法凑成容量5的背包
    已经有2(numsi)的话,有 dp3种方法凑成容量5的背包
    已经有3(numsi)的话,有 dp2中方法凑成容量5的背包
    已经有4(numsi)的话,有 dp1中方法凑成容量5的背包
    已经有5(numsi)的话,有 dp0中方法凑成容量5的背包
    只要有了numsi,凑成dpj就有dpj - nums\[i] 种方法,凑成dp5就是把所有的dpj - nums\[i] 累加起来。所以求组和类的递归公式: dp[j] += dp[j - nums[i]]
  3. dp数组初始化
    dp[0]初始化为1
  4. 确定遍历顺序
    nums放在外循环,target在内循环,且内循环倒序
cpp 复制代码
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        if (abs(target) > sum) return 0; // 此时没有方案
        if ((target + sum) % 2 == 1) return 0; // 此时没有方案
        int bagSize = (target + sum) / 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];
    }
};

时间复杂度:O(n × m),n为正数个数,m为背包容量

空间复杂度:O(m),m为背包容量

leetcode 474. 一和零

题目链接:一和零
本题中strs 数组里的元素就是物品,每个物品都是一个!
m 和 n相当于是一个背包,两个维度的背包

  1. dp数组及下标的含义
    dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dpij
  2. 确定递推公式
    dpij 可以由前一个strs里的字符串推导出来,strs里的字符串有zeroNum个0,oneNum个1。
    dpij 就可以是 dpi - zeroNumj - oneNum + 1。然后在遍历的过程中,取dpij的最大值。
    所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
    字符串的zeroNum和oneNum相当于物品的重量(weighti),物品的重量有两个维度。字符串本身的个数相当于物品的价值(valuei)。
  3. dp数组初始化
    物品价值不会是负数,初始为0,保证递推的时候dpij不会被初始值覆盖。
  4. 遍历顺序
    外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历。
cpp 复制代码
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);
        }
    }
}

整体代码如下:

cpp 复制代码
class Solution {
public:
    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];
    }
};

时间复杂度: O(kmn),k 为strs的长度

空间复杂度: O(mn)

相关推荐
wzdark15 小时前
基于堆的优先队列实现原理与复杂度分析4
算法
彧azz17 小时前
图的存储结构详解:邻接矩阵的原理、实现与应用
开发语言·数据结构·学习·php
老王熬夜敲代码17 小时前
BLAKE3:最快的密码学哈希函数
算法·密码学·哈希算法
hansang_IR17 小时前
【题解】P4460 [CQOI2018] 解锁屏幕
c++·算法
见闻小天地17 小时前
简博斯JG-C系列彩色激光同轴位移计:摄像头模组对位与行程测量的技术价值观察
人工智能·算法
葫三生18 小时前
《论三生原理》神话学构想与“神话历史”理论、《古史中的神话》思路异同?
大数据·人工智能·科技·深度学习·算法
liliangcsdn18 小时前
因子分析指标概念与示例
算法·机器学习
SupL!19 小时前
LoftQ原理
算法
Navigator_Z21 小时前
LeetCode //C - 1240. Tiling a Rectangle with the Fewest Squares
c语言·算法·leetcode
稻米哟21 小时前
力扣100——双指针
算法·leetcode