代码随想录算法训练营day36:动态规划04:1049.最后一块石头的重量II;494.目标和;474.一和零

news2024/9/25 15:27:18

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

力扣题目链接(opens new window)

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

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

如果 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,但是小于等于target——原型是:找到一个物品的子集,使其value值尽量贴近包的负荷值,但小于等于包的负荷值

其实也相当于是,每个石头前可以填写正号或者负号,要求最后运算结果尽量贴近于0——类似于目标和

类似昨天分割等和子集问题:dp[target]里是容量为target的背包所能背的最大重量。

最后的计算过程:

分成两堆石头,一堆石头的总重量是dp[target],另一堆就是sum - dp[target]。

在计算target的时候,target = sum / 2 因为是向下取整,所以sum - dp[target] 一定是大于等于dp[target]的。

那么相撞之后剩下的最小石头重量就是 (sum - dp[target]) - dp[target]。

#define MAX(a, b) (((a) > (b)) ? (a) : (b))

int getSum(int *stones, int stoneSize) {
    int sum = 0, i;
    for (i = 0; i < stoneSize; ++i)
        sum += stones[i];
    return sum;
}

int lastStoneWeightII(int* stones, int stonesSize){
    int sum = getSum(stones, stonesSize);
    int target = sum / 2;
    int i, j;

    // 初始化dp数组
    int *dp = (int*)malloc(sizeof(int) * (target + 1));
    memset(dp, 0, sizeof(int) * (target + 1));
    for (j = stones[0]; j <= target; ++j)
        dp[j] = stones[0];
    
    // 递推公式:dp[j] = max(dp[j], dp[j - stones[i]] + stones[i])
    for (i = 1; i < stonesSize; ++i) {
        for (j = target; j >= stones[i]; --j)
            dp[j] = MAX(dp[j], dp[j - stones[i]] + stones[i]);
    }
    return sum - dp[target] - dp[target];
}

494.目标和

力扣题目链接(opens new window)

难度:中等

给定一个非负整数数组,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。

分析:

为什么是0-1背包问题:给每一项前面添上+/-,可以看作2^n种可能性问题

——类似于找到两块子集,差为target——和石头问题是有一定相似程度的

target=(half+target)-half

并且要求2*half+target=total_sum

也就是前面填正号的部分之和=half+target

填负号的部分之和=half

——筛掉计算不出整数half的情况

**背包里存放的东西严格要求等于某个值

**需要计算多少种满足题意的方法

****不是太理解这个求和的思路!

1、dp数组:dp【j】填满j容量的包,最多有几种方法

2、递归关系:——有哪些来源可以推出dp[j]呢?

eg:目标是装5,已经装了物品1, 还有dp[4]种方法可以装满   

 装满背包的方法dp[ j ] += dp[ j-nums[ i ] ] 对i累加

3、初始化

应当从递推公式出发>>>式子本来的物理意义

从递推公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源,如果dp[0]是0的话,递推结果将都是0。

dp[j]其他下标对应的数值也应该初始化为0,从递推公式也可以看出,dp[j]要保证是0的初始值,才能正确的由dp[j - nums[i]]推导出来。——存在累加,必须全0初始化

4、顺序

第一层遍历物品

第二层遍历背包

或者换一种理解方式:用二维数组

**注意:数组赋值方式

int dp[numsSize+1][left+1];
memset(dp, 0, sizeof(dp));

用二维数组解决:更常规的思路!对于第i个元素,是放还是不放

int findTargetSumWays(int* nums, int numsSize, int target) {
    int sum=0,left;
    int i,j;
    for(int i=0;i<numsSize;i++){
        sum+=nums[i];
    }
    //排除比较特殊的情况
    if((sum+target)%2 != 0 || abs(target) > abs(sum)) return 0;
    left=(sum+target)/2;
    
    //学习数组的赋值方式
    int dp[numsSize+1][left+1];
    memset(dp, 0, sizeof(dp));
    dp[0][0]=1;
    
    for(i=1;i<=numsSize;i++){
        for(j=0;j<=left;j++){
            //要不要放nums[i]
            if(j<nums[i-1]) dp[i][j]=dp[i-1][j];
            else dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]];
        }
    }

    return dp[numsSize][left];   
}

一维数组+leetcode思路

int findTargetSumWays(int* nums, int numsSize, int target) {
    int sum=0,left;
    int i,j;
    for(int i=0;i<numsSize;i++){
        sum+=nums[i];
    }
    if((sum+target)%2 != 0 || abs(target) > abs(sum)) return 0;
    left=(sum+target)/2;

    int k[left+1];
    memset(k, 0, sizeof(k));
    k[0]=1;

    for (i=1;i<=numsSize;i++){
        for (j=left;j>=0;j--){
            if(j>=nums[i-1]) k[j]=k[j]+k[j-nums[i-1]]; 
        }
    }
    return k[left];
}

474.一和零

力扣题目链接(opens new window)

给你一个二进制字符串数组 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 。

示例 2:

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

分析:

确定dp数组(dp table)以及下标的含义:

dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。

——其实变成三维的问题了,也就是背包的重量有两个维度,物品有一个维度

但是把物品的维度变成滚动数组——所以还是两个维度

确定递推公式

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

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

然后我们在遍历的过程中,取dp[i][j]的最大值。

所以递推公式: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])。

dp数组如何初始化

因为物品价值不会是负数,01背包的dp数组初始化为0就可以。

确定遍历顺序

01背包+滚动数组:外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!

int findMaxForm(char** strs, int strsSize, int m, int n) {
    int dp[m+1][n+1];
    memset(dp, 0, sizeof(dp));
    int i,j,object;

    for (object=0;object<strsSize;object++){
        char *x=strs[object];
        int n1=0,n0=0;
        for (int k=0;k<strlen(x);k++){
            if(x[k]=='0') n0++;
            else n1++;
        }

        for(i=m;i>=0;i--){//背包维度都需要逆序哈!
            for(j=n;j>=0;j--){
                if (i>=n0 && j>=n1) dp[i][j]=fmax(dp[i][j], dp[i-n0][j-n1]+1);
            }
        }

    }
    return dp[m][n];
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WEB应用(十五)---文件包含

文件包含的概念 在各种开发语言中都提供了内置的文件包含函数&#xff0c;可以使得开发人员在一个代码文件中直接包含&#xff08;引入&#xff09;另外一个代码文件。 由于文件包含可以达到复用和方便修改的目的&#xff0c;在代码设计中常常使用。 大多数情况下&#xff0…

构建生成工具cmake的使用(2)

一.制作库文件 Linux下动态库是以 .lib开头&#xff0c;以 .so为结尾。静态库以 .lib 开头&#xff0c;.a为结尾。 Windows下动态库以dll为结尾&#xff0c;以 .lib为结尾 1.1.cmake编写生成动态库 我们想把add.cc和sub.cc打成一个动态库 …

Spring Boot 3.x Rest API最佳实践之统一响应结构

上一篇&#xff1a;Spring Boot 3.x Rest API最佳实践之API实现 下一篇&#xff1a;Spring Boot 3.x Rest API统一异常处理最佳实践 前面我们完成了电商示例API的设计和简单实现&#xff0c;本小节在此基础上完成统一响应结构的实战。 文章目录 定义Response响应体拦截Rest A…

【Day04】0基础微信小程序入门-学习笔记

文章目录 基础加强学习目标自定义组件1. 创建与引用2. 样式3. 数据、方法和属性4. 数据监听器5. 纯数据字段6. 组件生命周期6.1 created6.2 attached&#xff08;使用最多&#xff09;6.3 detached6.4 定义生命周期函数 7. 组件所在页面的生命周期7.1 定义使用7.2 生成随机的RG…

【QGroundControl二次开发】九. QGC地面站替换自定义MAVLINK协议

一. 生成自定义mavlink协议 具体操作参考之前文章->【QGroundControl二次开发】四.QGC自定义MAVLink消息 -------------------------下面为具体操作--------------------------- 在mavlink源码下的mavlink-master\message_definitions\v1.0\common.xml加入自定义协议&…

(javaweb)请求响应postman

目录 一.请求响应概述 二.请求参数的接收及封装 1.postman 2. 简单参数 3.实体参数 4.数组集合参数 5.日期参数 6.JSON参数 二.设置响应数据 一.请求响应概述 1.Tomcat又称为servlet容器 前端浏览器发起请求携带http请求数据&#xff0c;web服务器负责请求协议的解析&a…

网站开发涉及到的技术内容介绍——后端PHP(1)

一、PHP简介 PHP(全称:Hypertext Preprocessor (超文本预处理器))是一种创建动态交互性网站的服务器端脚本语言( PHP代码可以放在HTML文档中的任何位置;且PHP 脚本是在服务器上运行,然后将纯 HTML 结果发送回浏览器)且PHP 是免费的,并且使用非常广泛。同类的后端语言有…

Element学习(布局组件、案例操作)(4)

1、页面整体的布局 2、找到这种布局对应的代码&#xff08;复制——>粘贴到标签<div>中&#xff09; <el-container><el-header>Header</el-header><el-container><el-aside width"200px">Aside</el-aside><el-main…

8.8C++作业

在类结构体中&#xff0c;运用 成员函数或友元函数 实现算术运算符重载 #include <iostream>using namespace std;class Stu {friend const Stu operator/(const Stu &R,const Stu &L);friend const Stu operator%(const Stu &R,const Stu &L); private…

【2024年电赛H题自动行驶小车】省一学长手把手从零教你学MSPM0

一、前前言 第十二届浙江省大学生电子设计竞赛终于落下帷幕了&#xff0c;名单已公示&#xff0c;几家欢喜几家愁&#xff1f;我觉得每一位经历过电赛的朋友都称得上英雄&#xff0c;我想我们所学到的并非是“省一等”或“成功参赛奖”一个头衔能囊括的&#xff0c;相信真正有…

一篇带你了解kickstart无人值守以及pxe实现服务器自动部署

目录 使用背景 pxe原理 一、kickstart无人值守实验 实验环境&#xff1a; kickstart脚本制作&#xff1a; http服务 DCHP服务 定位需要装的机器上&#xff08;已使用光盘&#xff09; 二、PXE实验 实验环境&#xff1a;在上个实验环境的基础上 使用已经做好的dhcp&am…

Type-C取电芯片LDR6500

在当今电子设备日新月异的时代&#xff0c;Type-C接口以其高效、便捷的特点迅速成为市场主流。这一接口不仅支持高速数据传输&#xff0c;还实现了正反插拔的便利性&#xff0c;极大地提升了用户体验。然而&#xff0c;在Type-C接口的广泛应用背后&#xff0c;一个关键的技术组…

数模评价类—【主成分分析法】

目录 文章目录 前言 一、主成分分析法是什么&#xff1f; 二、模型原理 三.实现步骤 1.x标准化处理 2.计算标准化样本后的协方差矩阵/样本相关系数矩阵 3.计算R的特征值&#xff08;入&#xff09;和特征向量 4.计算主成分贡献率和累计贡献率 5.写出主成分 总结 前言…

【物联网设备端开发】使用QEMU模拟ESP硬件运行ESP-IDF

目录 一&#xff0c;开发环境搭建 1.1 安装ESP-IDF 1.2 安装vscode插件 1.3 在ESP-IDF插件配置ESP-IDF开发配置 1.4 下载IOTDeviceSDK 设备端开发代码 1.5 通过ESP-IDF插件编译好镜像 1.6 构建QEMU docker镜像 1.7 使用QEMU容器运行镜像 二&#xff0c;搭建QEMU环境步…

CS531 Virtualization

MLFQ copy and change address translation Segmentation TLB multilevel page

Qt实现中英文切换中QMessageBox中的中文信息怎么处理

有粉丝看了《Qt实现中英文切换》文章后&#xff0c;留言说“中英文切换中QMessageBox中的中文信息怎么处理”&#xff0c;这篇文章就告诉你处理方法。 1&#xff0c;QMessageBox OK或Cancel提示语句 QMessageBox::information(this, QString::fromLocal8Bit("测试")…

达林顿管uln2004a参数及其功耗计算

特点&#xff1a; 单输出集电极电流500mA高电压输出 50V有输出钳位二极管达林顿晶体管阵列。每个由七个组成NPN达林顿对&#xff0c;具有高压输出与共阴极钳位二极管开关感性负载。单个达灵顿对的集电极额定电流为500mA。达林顿对可以并联&#xff0c;以获得更大的电流能力 应…

【LVS】部署NAT模式集群

一、实验环境 每台主机的防火墙和SELinux都要关掉 systemctl stop firewalld setenforce 0 client&#xff08;测试机&#xff09;&#xff1a; ip 172.25.254.50 lvs&#xff08;调度器&#xff09;&#xff1a; vip 172.25.254.100 dip 192.168.0.100 RS1&#xff08;真实服…

2025深圳国际户外棋牌游戏休闲娱乐展览会

2025深圳国际户外棋牌游戏休闲娱乐展览会 2025 Shenzhen International Outdoor Chess Card Games, Leisure and Entertainment Exhibition 时间&#xff1a;2025年02月27-3月01日 地点&#xff1a;深圳会展中心&#xff08;福田馆&#xff09; 详询主办方陆先生 I38&…

LeetCode.3131.找出与数相加的整数I

题目描述&#xff1a; 给你两个长度相等的数组 nums1 和 nums2。 数组 nums1 中的每个元素都与变量 x 所表示的整数相加。如果 x 为负数&#xff0c;则表现为元素值的减少。 在与 x 相加后&#xff0c;nums1 和 nums2 相等 。当两个数组中包含相同的整数&#xff0c;并且这…