当前位置: 首页 > news >正文

算法训练营DAY36 第九章 动态规划part04

1049.最后一块石头的重量II

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

有一堆石头,每块石头的重量都是正整数。

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

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

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

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

示例:

  • 输入:[2,7,4,1,8,1]
  • 输出:1

解释:

  • 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
  • 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
  • 组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
  • 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。

本题目可以抽象为求一个目标重量为target=sum/2的背包;遍历所有石头,找到最接近target的背包数量;那么剩余石头的重量就是sum-dp[target];答案输出的就是这两堆石头的差值。

1、确定dp数组及下标含义

dp[j]表示容量为j的背包最多能装的石头重量

2、确定递推公式

dp[j]=max(dp[j],dp[j-stones[i]]+stones[i])

3、初始化dp数组

这里石头肯定不会是负数,所以只需要全部初始化为0;

4、确定递推顺序

外层循环遍历物品(石头);内层循环遍历重量;内层循环需要倒序,从target开始--;

5、举例推理

class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int sum=0;for(int i=0;i<stones.size();i++){sum+=stones[i];}int target;target=sum/2;vector<int> dp(15001,0);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];}
};

494.目标和

494. 目标和 - 力扣(LeetCode)

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

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例:

  • 输入:nums: [1, 1, 1, 1, 1], S: 3
  • 输出:5

解释:

  • -1+1+1+1+1 = 3
  • +1-1+1+1+1 = 3
  • +1+1-1+1+1 = 3
  • +1+1+1-1+1 = 3
  • +1+1+1+1-1 = 3

一共有5种方法让最终目标和为3。

思路:

把数组分为两部分x、y;根据题目条件我们知道x+y=sum;x-y=target;根据这两个方程,可以解出x、y;这里我们用x=(sum+target)/2;

回溯的思路也能解决问题,但是本题超时了;

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

动态规划 (二维dp数组)

这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。

本题则是装满有几种方法。其实这就是一个组合问题了。

1确定dp数组以及下标的含义

dp[i][j]:使用 下标为[0, i]的nums[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种方法。

2确定递推公式

本题中,物品i的容量是nums[i],价值也是nums[i]。

递推公式:dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]];

3dp数组如何初始化

先明确递推的方向,如图,求解 dp[2][2] 是由 上方和左上方推出。所以二维数组的最上行 和 最左列一定要初始化,这是递推公式推导的基础,

第一行

dp[0][j]:只放物品0, 把容量为j的背包填满有几种方法。

只有背包容量为 物品0 的容量的时候,方法为1,正好装满。

其他情况下,要不是装不满,要不是装不下。

所以初始化:dp[0][nums[0]] = 1 ,其他均为0 。

第一列

dp[i][0] : 背包容量为0, 放物品0 到 物品i,装满有几种方法。

都是有一种方法,就是放0件物品。

即 dp[i][0] = 1

但这里有例外,就是如果 物品数值就是0呢?其实就是算数组里有t个0,然后按照组合数量求,即 2^t 。

4确定遍历顺序

外层遍历nums;内层遍历背包,这里是二维dp数组,所以从上到下从左到右;

5举例推导dp数组

输入:nums: [1, 1, 1, 1, 1], target: 3

bagSize = (target + sum) / 2 = (3 + 5) / 2 = 4

dp数组状态变化如下:

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

474.一和零

474. 一和零 - 力扣(LeetCode)

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

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

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

示例 1:

  • 输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3

  • 输出:4

  • 解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

1、确定dp数组与下标含义

dp[i][j]表示组成最多有i个0j个1最大子集大小

2、确定递推公式

dp[i][j] 可以由前一个strs里的字符串推导出来,strs里的字符串有zeroNum个0,oneNum个1。

dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。

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

对比01背包的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); 可以发现,字符串的zeroNum和oneNum相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。

3、dp数组如何初始化

因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。

4、确定遍历顺序

外层便利物品也就是字符串;内层遍历背包(从后向前)

5、举例推导

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 s:strs){int oneNum=0,zeroNum=0;for(char c:s){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];}
};

http://www.xdnf.cn/news/1157311.html

相关文章:

  • Request和Response相关介绍
  • 数字图像处理(四:图像如果当作矩阵,那加减乘除处理了矩阵,那图像咋变):从LED冬奥会、奥运会及春晚等等大屏,到手机小屏,快来挖一挖里面都有什么
  • 《计算机网络》实验报告三 UDP协议分析
  • STM32-第八节-TIM定时器-4(编码器接口)
  • C++虚函数易错点整理
  • Python dataclass 高阶用法与技巧
  • springboot-profile
  • Direct3D 11学习(一)
  • 数学专业转行做大数据容易吗?需要补什么?
  • Web服务压力测试工具hey学习一:使用方法
  • 如何解决pip安装报错error subprocess-exited-with-error问题
  • 力扣面试150题--搜索插入位置
  • 30天打牢数模基础-灰色预测模型讲解
  • BLIP、InternVL Series(下)
  • Eureka+LoadBalancer实现服务注册与发现
  • JavaScript 对象操作、继承与模块化实现
  • RCE随笔(1)
  • 使用 Pyecharts 绘制精美饼状图:从基础到高级技巧
  • 【LeetCode 热题 100】236. 二叉树的最近公共祖先——DFS
  • Effective Python 条款13:通过带星号的unpacking操作来捕获多个元素,不要用切片
  • 构建一个简单的Java框架来测量并发执行任务的时间
  • 深入浅出理解动态规划
  • The FastMCP Client
  • `tidyverse` 中涉及的函数及其用法
  • 【RAG Agent】Deep Searcher实现逻辑解析
  • 【JS逆向基础】数据库之redis
  • 第一章: 初识 Redis:背后的特性和典型应用场景
  • 什么是 ELK/Grafana
  • 使用pytorch创建模型时,nn.BatchNorm1d(128)的作用是什么?
  • Muduo库中单例模式详解