代码随想录训练营day34| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果...

简介: 代码随想录训练营day34| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果...

前言

代码随想录算法训练营day34


一、Leetcode 1005.K次取反后最大化的数组和

1.题目

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

示例 1:

输入:nums = [4,2,3], k = 1 输出:5 解释:选择下标 1 ,nums 变为 [4,-2,3] 。

示例 2:

输入:nums = [3,-1,0,2], k = 3 输出:6 解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。

示例 3:

输入:nums = [2,-3,-1,5,-4], k = 2 输出:13 解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations

2.解题思路

方法一:从小到大修改每个负数

思路与算法

由于我们希望数组的和尽可能大,因此除非万不得已,我们应当总是修改负数,并且优先修改值最小的负数。因为将负数 −x−x 修改成 xx 会使得数组的和增加 2x2x,所以这样的贪心操作是最优的。

当给定的 KK 小于等于数组中负数的个数时,我们按照上述方法从小到大依次修改每一个负数即可。但如果 KK 的值较大,那么我们不得不去修改非负数(即正数或者 00)了。由于修改 00 对数组的和不会有影响,而修改正数会使得数组的和减小,因此:

1. 如果数组中存在 00,那么我们可以对它进行多次修改,直到把剩余的修改次数用完;
2. 
3. 如果数组中不存在 00 并且剩余的修改次数是偶数,由于对同一个数修改两次等价于不进行修改,因此我们也可以在不减小数组的和的前提下,把修改次数用完;
4. 
5. 如果数组中不存在 00 并且剩余的修改次数是奇数,那么我们必然需要使用单独的一次修改将一个正数变为负数(剩余的修改次数为偶数,就不会减小数组的和)。为了使得数组的和尽可能大,我们就选择那个最小的正数。
6. 
7. 需要注意的是,在之前将负数修改为正数的过程中,可能出现了(相较于原始数组中最小的正数)更小的正数,这一点不能忽略。

细节

为了实现上面的算法,我们可以对数组进行升序排序,首先依次遍历每一个负数(将负数修改为正数),再遍历所有的数(将 00 或最小的正数进行修改)。

然而注意到本题中数组元素的范围为 [−100,100][−100,100],因此我们可以使用计数数组(桶)或者哈希表,直接统计每个元素出现的次数,再升序遍历元素的范围,这样就省去了排序需要的时间。

3.代码实现

```java class Solution { public int largestSumAfterKNegations(int[] nums, int k) { Map freq = new HashMap (); for (int num : nums) { freq.put(num, freq.getOrDefault(num, 0) + 1); } int ans = Arrays.stream(nums).sum(); for (int i = -100; i < 0; ++i) { if (freq.containsKey(i)) { int ops = Math.min(k, freq.get(i)); ans += (-i) * ops * 2; freq.put(i, freq.get(i) - ops); freq.put(-i, freq.getOrDefault(-i, 0) + ops); k -= ops; if (k == 0) { break; } } } if (k > 0 && k % 2 == 1 && !freq.containsKey(0)) { for (int i = 1; i <= 100; ++i) { if (freq.containsKey(i)) { ans -= i * 2; break; } } } return ans; } }
```

二、Leetcode 134. 加油站

1.题目

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 1:

输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2] 输出: 3 解释: 从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油 开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油 开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油 开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油 开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油 开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。 因此,3 可为起始索引。

示例 2:

输入: gas = [2,3,4], cost = [3,4,3] 输出: -1 解释: 你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。 我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油 开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油 开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油 你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。 因此,无论怎样,你都不可能绕环路行驶一周。

提示:

1. gas.length == n
2. cost.length == n
3. 1 <= n <= 105
4. 0 <= gas[i], cost[i] <= 104

2.解题思路

方法一:一次遍历

思路与算法

最容易想到的解法是:从头到尾遍历每个加油站,并检查以该加油站为起点,最终能否行驶一周。我们可以通过减小被检查的加油站数目,来降低总的时间复杂度。

假设我们此前发现,从加油站 xx 出发,每经过一个加油站就加一次油(包括起始加油站),最后一个可以到达的加油站是 yy(不妨设 x

∑i=xygas[i]<∑i=xycost[i]∑i=xjgas[i]≥∑i=xjcost[i] (For all j∈[x,y)) i=x∑ygas[i]

第一个式子表明无法到达加油站 yy 的下一个加油站,第二个式子表明可以到达 yy 以及 yy 之前的所有加油站。

现在,考虑任意一个位于 x,yx,y 之间的加油站 zz(包括 xx 和 yy),我们现在考察从该加油站出发,能否到达加油站 yy 的下一个加油站,也就是要判断 ∑i=zygas[i]∑i=zygas[i] 与 ∑i=zycost[i]∑i=zycost[i] 之间的大小关系。

根据上面的式子,我们得到:

∑i=zygas[i]=∑i=xygas[i]−∑i=xz−1gas[i]<∑i=xycost[i]−∑i=xz−1gas[i]<∑i=xycost[i]−∑i=xz−1cost[i]=∑i=zycost[i]i=z∑ygas[i]=i=x∑ygas[i]−i=x∑z−1gas[i]

其中不等式的第二步、第三步分别利用了上面的第一个、第二个不等式。

从上面的推导中,能够得出结论:从 x,yx,y 之间的任何一个加油站出发,都无法到达加油站 yy 的下一个加油站。

在发现了这一个性质后,算法就很清楚了:我们首先检查第 00 个加油站,并试图判断能否环绕一周;如果不能,就从第一个无法到达的加油站开始继续检查。

3.代码实现

```java class Solution { public int canCompleteCircuit(int[] gas, int[] cost) { int n = gas.length; int i = 0; while (i < n) { int sumOfGas = 0, sumOfCost = 0; int cnt = 0; while (cnt < n) { int j = (i + cnt) % n; sumOfGas += gas[j]; sumOfCost += cost[j]; if (sumOfCost > sumOfGas) { break; } cnt++; } if (cnt == n) { return i; } else { i = i + cnt + 1; } } return -1; } }
```

三、Leetcode 135. 分发糖果

1.题目

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

1. 每个孩子至少分配到 1 个糖果。
2. 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2] 输出:5 解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:

输入:ratings = [1,2,2] 输出:4 解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。 第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

提示:

1. n == ratings.length
2. 1 <= n <= 2 * 104
3. 0 <= ratings[i] <= 2 * 104

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/candy

2.解题思路

方法一:两次遍历

思路及解法

我们可以将「相邻的孩子中,评分高的孩子必须获得更多的糖果」这句话拆分为两个规则,分别处理。

1. 左规则:当 ratings[i−1]<ratings[i]ratings[i−1]<ratings[i] 时,ii 号学生的糖果数量将比 i−1i−1 号孩子的糖果数量多。
2. 
3. 右规则:当 ratings[i]>ratings[i+1]ratings[i]>ratings[i+1] 时,ii 号学生的糖果数量将比 i+1i+1 号孩子的糖果数量多。

我们遍历该数组两次,处理出每一个学生分别满足左规则或右规则时,最少需要被分得的糖果数量。每个人最终分得的糖果数量即为这两个数量的最大值。

具体地,以左规则为例:我们从左到右遍历该数组,假设当前遍历到位置 ii,如果有 ratings[i−1]

在实际代码中,我们先计算出左规则 leftleft 数组,在计算右规则的时候只需要用单个变量记录当前位置的右规则,同时计算答案即可。

3.代码实现

```java class Solution { public int candy(int[] ratings) { int n = ratings.length; int[] left = new int[n]; for (int i = 0; i < n; i++) { if (i > 0 && ratings[i] > ratings[i - 1]) { left[i] = left[i - 1] + 1; } else { left[i] = 1; } } int right = 0, ret = 0; for (int i = n - 1; i >= 0; i--) { if (i < n - 1 && ratings[i] > ratings[i + 1]) { right++; } else { right = 1; } ret += Math.max(left[i], right); } return ret; } }
```
相关文章
|
缓存 编译器 程序员
【Qt 元对象系统04】 深入浅出Qt的QMetaObject:探索元对象的魔法
【Qt 元对象系统04】 深入浅出Qt的QMetaObject:探索元对象的魔法
1282 0
Java 通过IP获取对应的国家省份城市经纬度(离线文件方案)
一. 除了调用接口查询城市, 还可以通过离线文件查询城市, 使用GeoLite2 City库 二. 离线库下载地址: https://dev.maxmind.com/geoip/geoip2/geolite2/ 点击如下位置下载压缩文件 文件解压后有一个文件名为GeoLite2-City.
|
存储 XML 数据可视化
通用仓库元模型概述
通用仓库元模型(Common Warehouse metamodel,CWM)指定了可用于在分布式异构环境中的仓库工具、仓库平台和仓库元数据存储库之间轻松交换仓库和商业智能元数据的接口。
1110 0
通用仓库元模型概述
|
8月前
|
人工智能 Rust API
AI 乱写代码怎么破?使用 Context7 MCP Server 让 AI 写出靠谱代码!
本文通过实际案例演示了如何利用 Context7 MCP Server 解决 AI 编程助手中的代码幻觉问题和使用过时 API 的问题。借助 Context7 获取最新、最准确的代码建议,显著提升了 AI 生成的代码质量,从而有效提高了开发效率。
2202 10
AI 乱写代码怎么破?使用 Context7 MCP Server 让 AI 写出靠谱代码!
|
人工智能 缓存 异构计算
云原生AI加速生成式人工智能应用的部署构建
本文探讨了云原生技术背景下,尤其是Kubernetes和容器技术的发展,对模型推理服务带来的挑战与优化策略。文中详细介绍了Knative的弹性扩展机制,包括HPA和CronHPA,以及针对传统弹性扩展“滞后”问题提出的AHPA(高级弹性预测)。此外,文章重点介绍了Fluid项目,它通过分布式缓存优化了模型加载的I/O操作,显著缩短了推理服务的冷启动时间,特别是在处理大规模并发请求时表现出色。通过实际案例,展示了Fluid在vLLM和Qwen模型推理中的应用效果,证明了其在提高模型推理效率和响应速度方面的优势。
云原生AI加速生成式人工智能应用的部署构建
|
缓存 前端开发 JavaScript
前端性能优化:提升网页加载速度的10个技巧
【10月更文挑战第25天】在互联网时代,网页加载速度直接影响用户体验和搜索引擎排名。本文介绍了10个提升网页加载速度的技巧,包括减少HTTP请求、启用压缩、使用CDN、延迟加载非关键资源、优化图片、减少重定向、使用浏览器缓存、优化CSS和JavaScript、异步加载JavaScript以及代码分割。通过这些方法,可以显著提高网页性能,改善用户体验。
2777 5
|
JavaScript
基于Vue2或Vue3实现任意上下左右拖拽悬浮的元素,且配置为自定义的全局指令
这篇文章介绍了如何在Vue 2或Vue 3项目中实现一个自定义的全局指令`v-dragSwitch`,用于创建可以任意方向拖拽并悬浮的元素,同时包含边界处理的逻辑。
3993 2
基于Vue2或Vue3实现任意上下左右拖拽悬浮的元素,且配置为自定义的全局指令
|
弹性计算 关系型数据库 数据库
阿里云史上最大力度降价:2024年阿里云服务器降价后租用费用明细报价表整理
2024年阿里云年度首次官方降价,百款产品直降,平均降幅20%,最高降幅55%,阿里云希望通过此次大规模降价,让更多企业和开发者用上先进的公共云服务,加速云计算在中国各行各业的普及和发展。阿里云将下调部署在中国大陆地域的部分公共云产品(行业云不在本次价格调整范围内):包括云服务器ECS、云数据库RDS(MySQL、PostgreSQL、MariaDB)、云数据库Redis社区版、云数据库MongoDB、云数据库ClickHouse社区兼容版的特定规格包年/多年官网折扣价、节省计划(云服务器大陆地域ECS计算型节省计划、RDS MySQL全地域节省计划),以及对象存储服务 OSS 按量付费、预留
538 0
|
Java 测试技术 开发者
滚雪球学Java(09-9):Java中的三目运算符,你真的掌握了吗?
【2月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!!
423 1
|
消息中间件 Kafka Python
排查实时tail功能cpu占用过高问题
开发实时log功能时碰到的一些问题
5030 0