代码随想录算法训练营第三十六天|1049. 最后一块石头的重量 II 494. 目标和 474.一和零

news2024/9/24 11:23:22

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

题目:

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

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

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

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

示例 1:

输入:stones = [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],这就是最优值。

示例 2:

输入:stones = [31,26,33,21,40]
输出:5

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 100

思路:

这个问题可以通过动态规划来解决。

可以将其视为一个子集划分问题,其中我们试图将石头分成两堆,使得两堆石头的重量差最小。通过这种方式,剩下的最小重量就等于两堆重量的差值。

动态规划思路:

  1. 定义状态: 我们定义 dp[j] 表示在可以达到的总重量为 j 的情况下,是否可以通过某些石头的组合实现。

  2. 状态转移: 我们遍历每一块石头,并更新 dp 数组。对于每一个石头,我们可以选择要么将其加入当前的组合(即将其重量加入当前的总重量),要么不加入。

    因此,对于每一个石头 stone,我们从背包容量 j 从大到小进行遍历(j 必须大于等于 stone),并且更新 dp[j]

     

    这里 or 表示我们可以选择当前石头或者不选择当前石头。

  3. 求解: 我们最终要找的是所有可以达到的总重量 sum,并且我们要找到一个最接近 sum/2 的总重量 j。在这种情况下,剩余的最小重量就是 sum - 2 * j

  4. 初始化: 初始时,dp[0] = true,表示可以用 0 重量的组合(即没有石头)来达到 0 重量。

  5. 返回值: 返回 sum - 2 * j 的最小值,其中 j 是所有 dp[j]true 的最大值且 j <= sum/2

上代码:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = accumulate(stones.begin(), stones.end(), 0);
        int target = sum / 2;
        vector<bool> dp(target + 1, false);
        dp[0] = true;
        
        for (int stone : stones) {
            for (int j = target; j >= stone; --j) {
                dp[j] = dp[j] || dp[j - stone];
            }
        }
        
        for (int j = target; j >= 0; --j) {
            if (dp[j]) {
                return sum - 2 * j;
            }
        }
        return 0;
    }
};

494. 目标和

题目:

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

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

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

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

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 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
+1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入:nums = [1], target = 1
输出:1

提示:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

思路:

这个问题可以转换为一个子集和问题,并通过动态规划来解决。我们需要将数组划分为两个子集,使得一个子集的和为 P,另一个子集的和为 N。问题的目标是找到这样的 P 和 N,使得 P−N=target。

  1. 转换问题:

    给定的数组总和为 sum,则有: P + N = sum 和: P - N = target

    通过这两个公式,我们可以推导出: 2P = target + sum P = (target + sum) / 2

    因此,问题就变成了在数组中找到一个子集,使其和为 P。

  2. 检查可行性:

    为了使得 P 是一个有效的子集和,必须满足以下条件:

    • target + sum 必须是偶数。
    • P 必须是非负整数(即 P >= 0)。

    如果不满足这些条件,则返回 0。

  3. 定义状态:

    我们定义 dp[j] 表示从数组中选择一些元素,其和恰好为 j 的不同组合数。

  4. 状态转移:

    遍历数组 nums,对于每个元素 num,我们更新 dp 数组,从后往前遍历: dp[j] = dp[j] + dp[j - num] 这里,dp[j] 的更新是因为我们可以选择 num 来构造和为 j 的组合,或者不选择它。

  5. 初始化:

    初始时,dp[0] = 1,表示和为 0 的组合数为 1(即不选择任何元素)。

  6. 返回值:

    最终,我们返回 dp[P],它代表了构造出和为 P 的不同组合数。

上代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        if ((target + sum) % 2 != 0 || sum < abs(target)) {
            return 0;
        }
        int P = (target + sum) / 2;
        vector<int> dp(P + 1, 0);
        dp[0] = 1;

        for (int num : nums) {
            for (int j = P; j >= num; --j) {
                dp[j] += dp[j - num];
            }
        }

        return dp[P];
    }
};

474.一和零

题目:

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

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

思路:

这个问题可以看作是一个二维的 0/1 背包问题,在一个二维数组中,我们既要考虑 0 的数量限制,也要考虑 1 的数量限制。

动态规划思路:

  1. 定义状态: 我们定义 dp[i][j] 表示在最多有 i 个 0 和 j 个 1 的情况下,可以选择的最大子集的大小。

  2. 状态转移: 遍历每一个字符串 str,计算其包含的 0 和 1 的数量 zerosones,然后更新动态规划数组 dp。对于每一个 str,从背包容量 mn 开始反向遍历,更新 dp 数组:

    这里,dp[i][j] 的更新是因为我们可以选择 str 来增加当前集合的大小,或者不选择它。

  3. 初始化: dp[0][0] 初始化为 0,表示在没有 0 和 1 的情况下,最大子集的大小为 0。

  4. 返回值: 最终,dp[m][n] 就是我们要求的答案,表示在最多有 m 个 0 和 n 个 1 的情况下,能够选择的最大子集的大小。

上代码:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        
        for (const string& str : strs) {
            int zeros = count(str.begin(), str.end(), '0');
            int ones = str.size() - zeros;
            
            for (int i = m; i >= zeros; --i) {
                for (int j = n; j >= ones; --j) {
                    dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1);
                }
            }
        }
        
        return dp[m][n];
    }
};

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

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

相关文章

[Linux]:环境开发工具

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 软件包管理器——yum 1.1 yum的概念 在Linux系统中&#xff0c;如果想安…

【C++深入学习】日期类函数从无到有实现

零、本文思维导图 一、前期准备 1.1 检查构造的日期是否合法 //Date.cpp bool Date::CheckDate() {if (_month < 1 || _month > 12|| _day < 1 || _day > GetMonthDay(_year, _month)){return false;}else{return true;} }Date::Date(int year, int month, int d…

3.6 排序

在第一趟排序之后&#xff0c;一定能把数据表中最大或最小元素放在其最终位置上的排序算法是&#xff08; &#xff09;。 A. 冒泡排序 B. 直接插入排序 C. 快速排序 D. 归并排序 正确答案是 A。 解析 第i趟冒泡排序是从第1个元素到第n-i1个元素依次比较相邻两个元素的关键字&a…

0、Typescript学习

1、变量声明 let a:number100 2、常量 const b:number200 3、判断变量的类型 //number 表示数值类型&#xff0c;包括整数和浮点数 let a:number100 console.log(typeof a) 4、定义数组 let arr1:number[][1,2,3]console.log(arr1[0]) 5、定义函数 &#xff08;1&…

PVN3D(一)代码框架

在windows上配置pvn3d的环境一直配不成功&#xff0c;主要卡在了与C联合编译上&#xff0c;不知道如何处理了。索性先看看代码&#xff0c;竟然发现与论文中的代码对应上了。希望这一段时间把环境配置好。 1.论文中的网络结构 1.RGB图像特征&#xff0c;通过CNN提取特征。深度…

【前端面试】leetcode指针解法javascript

最大盛水 https://leetcode.cn/problems/container-with-most-water/ var maxArea = function(height) {// 左右指针靠拢let left = 0;let right = height.length-1;let maxArea = 0; while(left<right){// 计算出 当前的容积 与最大容积比较,取出最大的const currentAre…

牛客周赛 Round 58(ABCDF)

目录 A.会赢吗&#xff1f; B.能做到的吧 C.会赢的&#xff01; D.好好好数 F.随机化游戏时间 A.会赢吗&#xff1f; 思路&#xff1a; 签到题&#xff0c;比大小 void solve() {double a,b;cin>>a>>b;if(a>b) cout<<"NO";else cout<&…

前端请求的路径baseURL怎么来的 ?nodejs解决cors问题的一种方法

背景&#xff1a;后端使用node.js搭建&#xff0c;用的是express 前端请求的路径baseURL怎么来的 &#xff1f; 前后端都在同一台电脑上运行&#xff0c;后端的域名就是localhost&#xff0c;如果使用的是http协议&#xff0c;后端监听的端口号为3000&#xff0c;那么前端请求…

pdf怎么去水印?5个实用去水印方法新手必看(保姆级攻略)

pdf怎么去水印&#xff1f;在日常的办公工作生活中&#xff0c;我们常常需要使用PDF文件。pdf格式文件非常流行&#xff0c;因为它兼具稳定性和安全性。但是&#xff0c;有时我们从网上下载的pdf文件会带有水印&#xff0c;这些水印不仅影响了文件的美观&#xff0c;还影响了别…

turbovnc 服务端、客户端安装

turbovnc 可以方便地远程登录带界面的linux系统&#xff0c;比如xbuntu、kali等&#xff1b;远程windows11系统&#xff0c;经过亲身测试体验&#xff0c;感觉还是不如windows自带的rdp服务&#xff08;mstsc命令连接&#xff09;好用。 一、安装客户端 下载最新版本的客户端…

Java:位运算符,移位运算

一 位运算符 1.按位与------ & 运算法则&#xff1a; 2.按位或------ | 运算法则&#xff1a; 3.按位异或------ ^ 运算法则&#xff1a; 4.按位取反------ ~ 运算法则&#xff1a; 如果该位为 0 则转为 1, 如果该位为 1 则转为 0 二 移位运算 1.左移 << 运…

数据结构 双向链表

初始化 创建 遍历以及头插

Ubuntu 24.04 安装 英特尔工具包 Intel® Toolkits

目录 1.采用用户界面 GUI 安装英特尔基本工具包 Intel oneAPI Base Toolkit 1.1 下载离线英特尔基本工具包 1.2 安装英特尔基本工具包 1.3 英特尔基本工具包 Intel oneAPI Base Toolkit 环境设置 2.安装英特尔高性能计算工具包 Intel HPC Toolkit 2.1 下载离线英特尔高性…

学习大数据DAY52 Docker中的Mysql主从配置

Mysql 数据库主从同步 上机练习 1 容器生成命令 压缩包获取镜像 docker image load -i /root/mysql.tar 创建并开启两个镜像&#xff1a; docker run --name mysql1 -d -p 3333:3306 \ -v /opt/mysql1/conf:/etc/mysql/conf.d/ \ -v /opt/mysql1/data:/var/lib/mysql \…

精选整理!市面上7款AI论文生成器一键自动生成论文!

在当今学术研究和写作领域&#xff0c;AI技术的迅猛发展为研究人员提供了极大的便利。特别是AI论文自动生成助手&#xff0c;它们不仅能够提高写作效率&#xff0c;还能帮助生成高质量的论文内容。本文将详细介绍市面上7款超好用的AI论文生成器&#xff0c;并特别推荐千笔-AIPa…

kubernetes中的ParallelizeUntil()框架源码解读与使用

概述 摘要&#xff1a;本文从源码层面解读了kubernetes源码中常用的workqueue.ParallelizeParallelizeUntil()框架的源码实现&#xff0c;并且本文也将举例说明了workqueue.ParallelizeUntil()方法的典型使用场景。 正文 说明&#xff1a;基于 kubernetes v1.18.0 源码分析 …

Scratch教师节:给老师的一封信

小虎鲸Scratch资源站-免费Scratch作品源码,素材,教程分享平台! 【Scratch教师节特别献礼】—— 给老师的一封信&#xff1a;编程之光&#xff0c;照亮梦想之路 在这个金秋送爽、硕果累累的季节里&#xff0c;我们迎来了一个特别而温馨的日子——教师节。在这个充满感激与敬意的…

交叉编译概念

交叉编译概念 目录 交叉编译概念1. 什么是交叉编译2. 交叉编译的作用3. 交叉编译器4. 交叉编译工具链5. 交叉编译的一般步骤6. 交叉编译实例 1. 什么是交叉编译 交叉编译是指在一个平台上编译代码&#xff0c;使其能够在另一个不同的平台上运行的过程。这种编译方式通常用于开…

深入探索JDBC:Java数据库连接技术详解与实战应用

Java Database Connectivity&#xff08;JDBC&#xff09;是Java语言中用于访问关系型数据库的标准接口。它定义了一组API&#xff0c;使得Java程序能够以统一的方式连接、访问和操作不同的关系型数据库。JDBC不仅简化了数据库操作&#xff0c;还提高了Java应用程序的可移植性和…

抢先看:2024云栖大会体验攻略

这是一场「AI」奇妙之旅。 2024云栖大会定档 9月19日&#xff01; 期待与你在 杭州云栖小镇 共度一场为期3天的科技盛会 三日主论坛 400分论坛 与并行话题 4万平米 智能科技展区 免费领取云栖大会门票 怎么看、怎么玩、怎么逛 超长干货攻略奉上&#xff0c;请查收 ⬇️…