代码随想录算法训练营day41|动态规划04

最后一块石头的重量||

返回剩余最后一块石头石头最小的可能重量,那么就应该最后剩余的两块石头尽量都等于或接近总重量的一半,这样剩下的就是一半的质量

目标和

给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

回溯的方法

cpp 复制代码
class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
        if (sum == target) {
            result.push_back(path);
        }
        // 如果 sum + candidates[i] > target 就终止遍历
        for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
            sum += candidates[i];
            path.push_back(candidates[i]);
            backtracking(candidates, target, sum, i + 1);
            sum -= candidates[i];
            path.pop_back();

        }
    }
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        if (S > sum) return 0; // 此时没有方案
        if ((S + sum) % 2) return 0; // 此时没有方案,两个int相加的时候要格外小心数值溢出的问题
        int bagSize = (S + sum) / 2; // 转变为组合总和问题,bagsize就是要求的和

        // 以下为回溯法代码
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); // 需要排序
        backtracking(nums, bagSize, 0, 0);
        return result.size();
    }
};

解释:假设加法的总和为x,那么减法对应的总和就是sum - x。所以我们要求的是 x - (sum - x) = target,x = (target + sum) / 2,且若(target+sum)%2!=0的话,x就是无解的

本题要求的,就是装满j的背包有多少种方案,
不放物品i:即背包容量为j,里面不放物品i,装满有dpi - 1j中方法。
放物品i: 即:先空出物品i的容量,背包容量为(j - 物品i容量),放满背包有 dpi - 1j - 物品i容量 种方法

如何初始化

最左上角的元素,如果背包容量为0,就放0种物品,所以就是1种方法,

最左列也应该是为0,但如果存在元素为0的情况,则如下

二维数组的代码

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<vector<int>> dp(nums.size(),vector<int>(bagSize+1,0));
        if(nums[0]<=bagSize) dp[0][nums[0]]=1;
        dp[0][0]=1;
        int numZero=0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]==0) numZero++;
            dp[i][0]=(int) pow(2.0,numZero);//最左列向下递增
        }
        for(int i=1;i<nums.size();i++){
            for(int j=0;j<=bagSize;j++){
                if(nums[i]>j) dp[i][j]=dp[i-1][j];
                else dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i]];
            }
        }
        return dp[nums.size()-1][bagSize];
    }
};

一维的方法初始化起来更简单

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];
    }

总结:在求装满背包有几种方法的情况下,递推公式一般为:dpj+=dpj-nums\[i];

一和零

一道01背包问题,但这个背包有两个维度,一个是m,一个是n

dpij:最多有i个0和j个1的strs的最大子集的大小为dpij。dpij = max(dpij, dpi - zeroNumj - oneNum + 1);字符串的zeroNum和oneNum相当于物品的重量(weighti),字符串本身的个数相当于物品的价值(valuei)。

注意!!!这里01背包都是从后往前遍历,因为是相当于两个一维动规的叠加

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];}
};
相关推荐
苦瓜小生14 分钟前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试
不会就选b28 分钟前
算法日常・每日刷题--<贪心>5
算法
圣保罗的大教堂37 分钟前
leetcode 2029. 石子游戏 IX 中等
leetcode
刘广睿1 小时前
素材去重为什么难?文件指纹、感知哈希与相似度判定的设计笔记
算法·哈希算法·产品设计·素材管理
少司府1 小时前
C++进阶:智能指针
开发语言·数据结构·c++·b树·算法·c·智能指针
鹿角片ljp2 小时前
LeetCode 22:括号生成|回溯dfs、剪枝与 char[] 覆盖代替撤销
算法·深度优先
sylviiiiiia2 小时前
leetcode hot100
python·算法·leetcode
纪伊路上盛名在2 小时前
Kabsch算法的Julia实现
开发语言·算法·julia·序列分析·蛋白质·rmsd
裕晟资质规划2 小时前
军工保密资质二级申报的四个可量化硬条件:条文位置、数值口径与西安配套企业实务要点
java·服务器·网络·数据库·算法
LuminousCPP2 小时前
数据结构-排序(一):基础排序算法横向对比|冒泡、插入、希尔、堆与双向选择,详解二分 / Knuth 增量
c语言·数据结构·笔记·算法·排序算法