【力扣刷题 | 第二十四天】

目录

前言:

[1049. 最后一块石头的重量 II - 力扣(LeetCode)](#1049. 最后一块石头的重量 II - 力扣(LeetCode))

[494. 目标和 - 力扣(LeetCode)](#494. 目标和 - 力扣(LeetCode))

总结:


前言:

今天我们依然暴打动态规划

1049. 最后一块石头的重量 II - 力扣(LeetCode)

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;

如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

这个问题其实很好想:我们如何把石头尽可能的撞碎呢?

很简单,我们在大体上把这些石头分成重量相似的两堆,因为如果两堆石头的重量相似,那么相撞后就一定会得到最小的值。

因此从动态分类的角度来讲,我们可以把这道题理解为是 一个重量为(sum/2)的背包,我们尽可能的装背包,之后装进背包的是一堆石头,未装进背包的是一堆石头,那么这两堆石头相减,就可以得到最小的石头重量。

那么我们就又把这道题转化为了 装与不装的01背包问题

其实这道题和我们前天做的分割等和子集是基本相同的,感兴趣的朋友可以去看一下那道题

那么既然是动态规划问题,我们就继续进行动态规划五部曲:

1.确定dp数组及其含义:dp[j] 是背包含量为j的时候所背的最大价值(在这里我们重量就是价值,价值就是重量)

2.递推公式 dp[j] = max(dp[j] , dp[ j - stones[i] ]+stones[i])

里层的减是减去容量,外面的加是加上价值,只不过是因为我们的重量和价值是一样的

3.确定初始化:全部初始化为0即可

cpp 复制代码
class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
            int sum=0;
            vector<int>dp(1501,0);
        for(int a : stones)
        {
            sum=sum+a;
        }

        int target = sum/2;

        for(int i=0;i<stones.size();i++)
        {
            for(int j= target;j>=stones[i];j--)
            {
                 dp[j] = max(dp[j] , dp[ j - stones[i] ]+stones[i]);
            }
        }
        return sum-dp[target]-dp[target];
    }
};

在这里我们要特别对末尾进行说明,为什么是 return sum-dp[target]-dp[target];

其实很好理解,因为这里的dp数组是一堆石头,而我们用sum-dp数组就得到了另外一堆石头的重量,再减一次dp数组,实际就是模拟两堆石头进行碰撞。

494. 目标和 - 力扣(LeetCode)

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

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

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

这道题其实我们可以这样理解:

一共有两个集合,两个集合分别装数字,设置目标值target,询问有几种可能使得两个集合相减的数字等于target

再优化一下:

我们可以把target也作为一个数字加到这两个集合的待选序列,询问有几种可能 使得两个集合的值相等

再转化一下思维:

,而target只有一个,也就是只能永远出现在一侧,另外一侧始终没有target,那么我们始终求没有target的那一侧不就好了嘛,换句话说,不就是在给定集合里面寻找有多少个集合的值等于(sum+target)/2/

那么我们不就又把这道题转化为了背包问题嘛?只不过以前我们总是在求是否有一种方法能把背包装满,现在求的是有多少种方法把背包装满。

因此我们按照动态规划五部曲走:

1.确定dp数组的含义:dp[j] 表示填满容量为j的背包最多有dp[j]种方法,例如dp[2]是指填满容量为2的背包最多有dp[2]种方法。

2.确定递推公式:dp[j]+=dp[j-nums[i]];

cpp 复制代码
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum=0;
        for(int a : nums)
        {
            sum=sum+a;
        }

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

总结:

动态规划想清楚之后直接爆杀。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
焜昱错眩..2 小时前
代码随想录算法训练营第三十九天|62.不同路径 63.不同路径ll
算法
焦耳加热5 小时前
阿德莱德大学Nat. Commun.:盐模板策略实现废弃塑料到单原子催化剂的高值转化,推动环境与能源催化应用
人工智能·算法·机器学习·能源·材料工程
wan5555cn5 小时前
多张图片生成视频模型技术深度解析
人工智能·笔记·深度学习·算法·音视频
u6066 小时前
常用排序算法核心知识点梳理
算法·排序
蒋星熠8 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
小欣加油8 小时前
leetcode 面试题01.02判定是否互为字符重排
数据结构·c++·算法·leetcode·职场和发展
3Cloudream8 小时前
LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解
算法·leetcode·字符串·双指针·滑动窗口·哈希表·中等
王璐WL9 小时前
【c++】c++第一课:命名空间
数据结构·c++·算法
空白到白9 小时前
机器学习-聚类
人工智能·算法·机器学习·聚类
索迪迈科技9 小时前
java后端工程师进修ing(研一版 || day40)
java·开发语言·学习·算法