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

本文主要是介绍代码随想录第34天| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

贪心算法,这不就是常识?还能叫贪心?LeetCode:1005.K次取反后最大化的数组和_哔哩哔哩_bilibili

给你一个整数数组 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] 。

提示:

  • 1 <= nums.length <= 104
  • -100 <= nums[i] <= 100
  • 1 <= k <= 104

 第一次贪心:局部最优:绝对值最大的负数变成正数;全局最优:和最大

第二次贪心:局部最优:数值小的正数变成负数;全局最优:和最大

具体步骤:

1、将数组按照绝对值大小从大到小排列

2、遍历数组

3、遇到负数就将负数变为正数,同时k--

4、负数改完了k仍然不为0、

5、将数组末尾的最小的正数值反复变负数又变正数,直到k=0

class Solution {public int largestSumAfterKNegations(int[] nums, int K) {// 将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小nums = IntStream.of(nums)  // 将原始数组转换为 IntStream.boxed()  // 装箱,将基本数据类型转换为包装类型,以便使用 sorted 方法.sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1))  // 按绝对值大小排序.mapToInt(Integer::intValue).toArray();  // 将排序后的 IntStream 转换为 int 数组int len = nums.length;  // 数组长度for (int i = 0; i < len; i++) {// 从前向后遍历,遇到负数将其变为正数,同时 K--if (nums[i] < 0 && K > 0) {nums[i] = -nums[i];  // 将负数变为正数K--;  // K 减一}}// 如果 K 还大于 0,那么反复转变数值最小的元素,直到 K 用完if (K % 2 == 1) nums[len - 1] = -nums[len - 1];  // 如果 K 为奇数,将最后一个元素变为负数return Arrays.stream(nums).sum();  // 返回数组元素的和}
}

134. 加油站 

134. 加油站 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站_哔哩哔哩_bilibili

在一条环路上有 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 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。

提示:

  • gas.length == n
  • cost.length == n
  • 1 <= n <= 105
  • 0 <= gas[i], cost[i] <= 104

假设有以下情况:

当汽车从下标为0的位置开始走,当走到下标为3的位置时, 剩余的油不够在这里的消耗,所以没有办法走到尾部,此时从下标为4的位置重新开始走,代码如下:

class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {// 初始化当前累计油量、总累计油量和起始加油站索引int curSum = 0;int totalSum = 0;int index = 0;// 遍历每个加油站for (int i = 0; i < gas.length; i++) {// 计算当前累计油量和总累计油量curSum += gas[i] - cost[i];totalSum += gas[i] - cost[i];// 如果当前累计油量为负,则说明无法从当前加油站出发,更新起始加油站索引,并将当前累计油量重置为0if (curSum < 0) {index = (i + 1);curSum = 0;}}// 如果总累计油量为负,则说明无法绕行一圈,返回-1;否则返回起始加油站索引if (totalSum < 0) return -1;return index;}
}

135. 分发糖果 

135. 分发糖果 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

贪心算法,两者兼顾很容易顾此失彼!LeetCode:135.分发糖果_哔哩哔哩_bilibili

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

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

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

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

示例 1:

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

示例 2:

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

提示:

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

精髓在于不要同时比较左右

先从前向后遍历确定右边评分大于左边的情况,再从后往前遍历确定左边评分大于右边的情况。

从前向后遍历确定右边评分大于左边的情况:

局部最优:右边评分比左边大,右边的孩子就多一颗糖果;全局最优:相邻孩子中,评分高的右孩子比左孩子获得更多的糖果。

 for (int i = 1; i < len; i++) {candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;}

此时结果如图:

再确定左孩子大于右孩子的情况(从后向前遍历):

// 第二次遍历,从右往左分糖果,只要左边的孩子评分比右边的大,左边的孩子的糖果数应该取本身的糖果数和右边孩子糖果数 + 1 二者的最大值for (int i = len - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) {candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);}}

综合代码:

class Solution {/*** 分两个阶段* 1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1* 2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大*/public int candy(int[] ratings) {int len = ratings.length;  // 计算评分数组的长度int[] candyVec = new int[len];  // 创建一个与评分数组等长的数组,用于存储每个孩子分到的糖果数量candyVec[0] = 1;  // 第一个孩子至少分到一个糖果// 第一次遍历,从左往右分糖果,只要右边的孩子评分比左边的大,右边的孩子糖果数就比左边多1for (int i = 1; i < len; i++) {candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;}// 第二次遍历,从右往左分糖果,只要左边的孩子评分比右边的大,左边的孩子的糖果数应该取本身的糖果数和右边孩子糖果数 + 1 二者的最大值for (int i = len - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) {candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);}}// 计算总共需要的糖果数int ans = 0;for (int num : candyVec) {ans += num;}return ans;  // 返回总共需要的糖果数}
}

这篇关于代码随想录第34天| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/887016

相关文章

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave