算法刷题|1049.最后一个块石头的重量||、494.目标和、474.一和零

news2024/11/25 22:44:17

最后一个块石头的重量||

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

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

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

思路:可以将所有的石头尽量分成重量近似相等的两堆,这样碰撞之后剩下的石头的重量就回事最小的,本题可以抽象成0-1背包:物品就是所有的石头,背包的容量就是sum/2

二维dp数组

  • dp[i][j]的含义:对于前i个物品,容量为j的背包,可以装的最大价值为dp[i][j]
  • 递推公式:dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-stones[i-1]]+stones[i-1]
  • dp数组的初始化:dp[i][0] = 0,dp[0][j] = 0
  • 遍历顺序:先遍历物品(从小大到),后遍历背包(从小到大)
  • 打印dp数组:debug使用
class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for(int i : stones){
            sum += i;
        }
        // 物品
        int N = stones.length;
        // 背包 
        int target = sum / 2;
        int[][] dp = new int[N+1][target+1];
        for(int i = 1;i<=N;i++){
            for(int j = 1;j<=target;j++){
                if(j < stones[i-1]){
                    dp[i][j] = dp[i-1][j];
                }else{
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-stones[i-1]]+stones[i-1]);
                }
            }
        }
        // dp[N][target]是实际上最后背包的最大价值,不一定等于target,所有下面计算的时候需要使用dp[N][target]而不是target
        // 为什么不需要取绝对值,因为target的取值是向下取整的,所有sum-target 一定大于 target
        return sum - dp[N][target] - dp[N][target];
    }
}

一维dp数组

  • dp[j]的含义:当背包容量为j的时候,能够装的最大价值为dp[j]
  • 递推公式:dp[j] = Math.max(dp[j],dp[j-stones[i]]+stones[i])
  • dp数组的初始化:dp[0] = 0
  • 遍历顺序:先遍历物品(从小到大),在遍历背包(从大到小)
  • 打印dp数组
class Solution {
    public int lastStoneWeightII(int[] stones) {
       int sum = 0;
       for(int i : stones){
           sum += i;
       }
       int target = sum / 2;
       int[] dp = new int[target + 1];
       dp[0] = 0;
       for(int i = 0;i<stones.length;i++){
           for(int j = target;j>=stones[i];j--){
               dp[j] = Math.max(dp[j],dp[j-stones[i]]+stones[i]);
           }
       }
       return sum - dp[target] - dp[target];
    }
}

目标和

题目:给你一个整数数组 nums 和一个整数 target 。

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

例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目

二维数组

思路:我们假设将nums数组分成两个集合,一个集合A全是’+‘,集合B全是’-',那么就有如下的公式
目标和
然后我们就需要求sum(A)的组合有多少就可以了

  • dp[i][j]的含义:对于前i个数,选择任意的数的和为j,总共有dp[i][j]种方式
  • 递推公式:dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]],这里需要求总共有多少种方式,所以需要加上以前的
  • dp数组的初始化:dp[0][0] = 1,因为对于0个数字,表达式的和为0,总共有1一种方式;不能初始化为0,因为根据递推公式来看,后面的值依赖前面的值,如果初始化为0的话,那么后面的所有的值都会是0
  • 遍历顺序:先遍历物品(从小到大),后遍历背包(从小到大)
  • 打印dp数组
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int n = nums.length;
        int sum = 0;
        for(int i : nums){
            sum+=i;
        }
        if(target < 0 && (sum + target) < 0) return 0;
        if((sum + target) % 2 != 0) return 0;
        int w = (sum + target) / 2;
        int[][] dp = new int[n+1][w+1];
        dp[0][0] = 1;
        for(int i = 1;i<=n;i++){
            for(int j = 0;j<=w;j++){
                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[n][w];
    }
}

一维数组

  • dp[j]的含义:填满容量为j的背包的方法有dp[j]种
  • 递推公式:dp[j] += dp[j-nums[i]]
  • dp数组初始化:dp[0] = 1
  • 遍历顺序:先遍历物品(从小到大),后遍历背包(从大到小)
  • 打印dp数组
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int n = nums.length;
        int sum = 0;
        for(int i : nums){
            sum+=i;
        }
        // 如果和为奇数,就不能平分,就不可能存在表达式加起来等于target
        if((sum + target) % 2 == 1) return 0;
        // 数组的和小于target的绝对值的时候也不会有方案
        if(sum < Math.abs(target)) return 0;
        int w = (sum + target) / 2;
        int[] dp = new int[w+1];
        dp[0] = 1;
        for(int i = 0;i<n;i++){
            for(int j = w;j>=nums[i];j--){
                // 这里为什么没有+nums[i]了,因为我们求的是方法数,如果选择当前物品i,那么总共的方案就取决于j-nums[i]的方案有多少,而不是背包的价值,只有在求价值的时候才需要加上
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[w];
    }
}

一和零

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

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

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

思路:本题同样可以抽象成0-1背包的问题,物品就是strs数组中的元素,背包容量就是m个0和n个1,只是本题的背包容量存在两个维度

  • dp[i][j]的含义:有i个0和j个1的最大长度的子集(背包)的长度是dp[i][j]
  • 递推公式:dp[i][j] = Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1)
    • 为什么这里是+1,而不是之前的+nums[i],因为本题求的个数,而不是最大价值,所有固定+1
  • dp数组初始化:dp[0][0] = 0
  • 遍历顺序:先遍历物品(从小到大),后遍历背包(从大到小)
  • 打印dp数组
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        dp[0][0] = 0;

        // 填充dp数组
        for(String str : strs){// 遍历物品
            // 统计每个字符串中的0 和 1 分别有多少个
            int zeroNum = 0,oneNum = 0;
            for(int i = 0;i<str.length();i++){
                if(str.charAt(i) == '0'){
                    zeroNum++;
                }else{
                    oneNum++;
                }
            }

            // 遍历背包
            for(int i = m;i>=zeroNum;i--){
                for(int j = n;j>=oneNum;j--){
                    // 这里+1,就相当于+nums[i],只是这里要求的不是价值,而是个数,所有固定+1
                    dp[i][j] = Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1);
                }
            }
        }
        return dp[m][n];
    }
}

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

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

相关文章

HBase的表设计笔记

HBase的RowKey设计 HBase是三维有序存储的&#xff0c;通过rowkey&#xff08;行键&#xff09;&#xff0c;column key&#xff08;column family和qualifier&#xff09;和TimeStamp&#xff08;时间戳&#xff09;这个三个维度可以对HBase中的数据进行快速定位。 HBase中row…

中国能源网络安全大会举办,腾讯安全曹文炎分享助力能源企业安全建设的实践经验

2023年4月20日-21日&#xff0c;由中国能源研究会主办的“2023年中国能源网络安全大会”&#xff08;以下简称“大会”&#xff09;在南京召开。大会以“新形势新安全”为主题&#xff0c;围绕提升我国能源行业网络安全水平&#xff0c;增强和维护我国能源网络安全能力&#xf…

Pytorch的CNN,RNNLSTM

CNN 拿二维卷积举例&#xff0c;我们先来看参数 卷积的基本原理&#xff0c;默认你已经知道了&#xff0c;然后我们来解释pytorch的各个参数&#xff0c;以及其背后的计算过程。 首先我们先来看卷积过后图片的形状的计算&#xff1a; 参数&#xff1a; kernel_size &#xff…

【AI炼丹术】写深度学习代码的一些心得体会

写深度学习代码的一些心得体会 体会1体会2体会3总结内容来源 一般情况下&#xff0c;拿到一批数据之后&#xff0c;首先会根据任务先用领域内经典的Model作为baseline跑通&#xff0c;然后再在这个框架内加入自己设计的Model&#xff0c;微调代码以及修改一些超参数即可。总体流…

Matlab进阶绘图第18期—相关性气泡热图

相关性气泡热图是一种特殊的气泡热图。 与一般的气泡热图相比&#xff0c;其数值位于[-1 1]区间&#xff0c;其颜色用于表示正负&#xff0c;而其气泡的大小用于表示数值绝对值的大小&#xff0c;可以十分直观地对两个变量的相关性进行分析。 由于Matlab中未收录相关性气泡热…

In-Context Learning中的示例选择及效果

一. ICL的背景 大型语言模型&#xff08;LLM&#xff09;如GPT-3是在大规模的互联网文本数据上训练&#xff0c;以给定的前缀来预测生成下一个token&#xff08;Next token prediction&#xff09;。这样简单的训练目标&#xff0c;大规模数据集以及高参数量模型相结合&#x…

国内可直接使用的OpenAI DALL*E 图片AI体验站,可通过自然语言生成图片

体验站最终演示效果 国内可直接使用的图片AI体验站&#xff1a;https://zizhu888.cn/text2img/index.html ChatGPT3.5 Turbo国内体验站: https://zizhu888.cn/chatgpt/index.html OpenAI DALL*E可以通过自然语言生成图片&#xff0c;内容创作者的福音&#xff0c;大大降低了创…

基于飞桨 PaddleVideo 的骨骼行为识别模型 CTR-GCN

main.pysame_seedsparse_argsmain ensemble.pyconfigs 文件夹Joint&#xff08;J&#xff09;的配置文件ctrgcn_fsd_J_fold0.yamlctrgcn_fsd_J_fold1.yaml Joint Angle&#xff08;JA&#xff09;的配置文件ctrgcn_fsd_JA_fold0.yaml paddlevideo 文件夹utils 文件夹__init__.p…

【Python 协程详解】

0.前言 前面讲了线程和进程&#xff0c;其实python还有一个特殊的线程就是协程。 协程不是计算机提供的&#xff0c;计算机只提供&#xff1a;进程、线程。协程是人工创造的一种用户态切换的微进程&#xff0c;使用一个线程去来回切换多个进程。 为什么需要协程&#xff1f; …

中国制造再击败一家海外企业,彻底取得垄断地位

中国制造已在13个行业取得领先优势&#xff0c;凸显出中国制造的快速崛起&#xff0c;日前中国制造又在一个行业彻底击败海外同行&#xff0c;再次证明了中国制造的实力。 一、海外企业承认失败 提前LGD宣布它位于广州的8.5代液晶面板生产线停产&#xff0c;预计该项目将出售给…

crm day03 创建市场活动

页面切割 div切割&#xff0c;ifram显示 如何分割的呢&#xff0c;在主页面上打开iframe $(function(){ //页面加载时window.open("workbench/main/index.do","workareaFrame"); })注意所有在WEB-INF的页面都会收到保护&#xff0c;因此到达此目录下的页…

不得不的创建型模式-建造者模式

目录 建造者模式是什么 下面是一个简单的示例代码&#xff0c;演示了如何使用建造者模式来构建一个复杂对象&#xff1a; 面试中可能遇到的问题及回答&#xff1a; 建造者模式是什么 建造者模式是一种创建型模式&#xff0c;它的目的是将复杂对象的构造过程分离成多个简单的…

你知道项目进度控制和跟踪的目的是什么吗?

项目进度控制和跟踪的目的是&#xff1a; 增强项目进度的透明度&#xff0c;当项目进展与项目计划出现偏差时&#xff0c;可以及时采取适当的措施。 1、计划是项目监控的有效手段 项目控制的手段是根据计划对项目的各项活动进行监控&#xff0c;项目经理可以使用甘特图来制…

界面控件DevExtreme使用指南 - 折叠组件快速入门(二)

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

微信小程序nodejs+python+php+springboot+vue 微型整容医美挂号预约app系统

(a) 管理员&#xff1b;管理员使用本系统涉到的功能主要有首页、个人中心、用户管理、体检预约管理、项目预约、系统管理等功能 (b) 用户&#xff1b;用户进入app可以实现首页、美容产品、我的等&#xff0c;在我的页面可以对在线预约、体检预约、项目预约等功能进行操作 本基于…

Unity之OpenXR+XR Interaction Toolkit实现 UI交互

一.前言 在VR中我们经常会和一些3D的UI进行交互&#xff0c;今天我们就来说一下如何实现OpenXRXRInteraction Toolkit和UI的交互。 二.准备工作 有了前两篇的配置介绍,我们就不在详细说明这些了&#xff0c;大家自行复习 Unity之OpenXRXR Interaction Toolkit接入Pico VR一体…

钉钉用一条斜杠,金山系用一张表格,做了华为一直想做的事

阿里的“新钉钉”又一次站在风口上 一场疫情导致数万企业停工的同时&#xff0c;却让阿里的钉钉、腾讯会议&#xff0c;还有字节跳动的飞书等在线协同办公产品火得一塌糊涂。 今天&#xff0c;OpenAI公司的一个chatGPT,让阿里、百度等各大互联网巨头扎堆发布大模型产品。 回顾…

如何在Web上实现激光点云数据在线浏览和展示?

无人机激光雷达测量是一项综合性较强的应用系统&#xff0c;具有数据精度高、层次细节丰富、全天候作业等优势&#xff0c;能够精确测量三维现实世界&#xff0c;为各个行业提供了丰富有效的数据信息。但无人机激光雷达测量产生的点云数据需要占用大量的存储空间&#xff0c;甚…

Gantt图和PERT图的相关知识

1、Gantt 图 Gantt图以时间为基准描述项目任务&#xff0c;可以清晰的描述每个任务从何时开始&#xff0c;到何时结束&#xff0c;以及每个任务的并行关系&#xff0c;但是不能反映项目各任务之间的依赖关系&#xff0c;也无法确定整个任务的关键所在。 2、PERT图 计划评审…

Canvas实现动态绘制圆周效果(沿圆周运动的圆的绘制)

步骤实现&#xff1a; 首先&#xff0c;创建一个 HTML 画布和一个 JavaScript 动画函数。 在画布上绘制一个圆。 定义一个变量来表示圆心的坐标和半径。 进行动画循环以更新圆心坐标&#xff0c;使其沿外圆周运动。 使用三角函数&#xff08;如 sin 和 cos&#xff09;来计…