代码随想录 贪心算法-中等题目-序列问题

news2024/12/27 0:07:12

376.摆动序列

376. 摆动序列

中等

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。

示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

示例 3:

输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

进阶:你能否用 O(n) 时间复杂度完成此题?

class Solution {  
    // 定义一个公共方法wiggleMaxLength,接收一个整数数组nums作为参数,返回摆动长度  
    public int wiggleMaxLength(int[] nums) {  
        // 如果数组长度小于等于1,则摆动长度等于数组长度  
        if (nums.length <= 1) {  
            return nums.length;  
        }  
          
        // 当前差值,初始化为0  
        // 表示当前元素与前一个元素的差值  
        int curDiff = 0;  
          
        // 上一个差值,初始化为0  
        // 表示前一个元素与前一个元素的差值  
        // 在第一次循环时,preDiff实际上是一个“初始值”,用于比较  
        int preDiff = 0;  
          
        // 摆动长度,初始化为1  
        // 因为至少有一个元素,所以摆动长度至少为1  
        int count = 1;  
          
        // 从数组的第二个元素开始遍历  
        for (int i = 1; i < nums.length; i++) {  
            // 计算当前差值  
            curDiff = nums[i] - nums[i - 1];  
              
            // 判断当前差值与上一个差值的符号是否相反  
            // 如果相反,说明摆动长度增加  
            // 注意:curDiff > 0 && preDiff <= 0 表示当前差值为正,且上一个差值为负或零  
            // curDiff < 0 && preDiff >= 0 表示当前差值为负,且上一个差值为正或零  
            if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {  
                count++; // 摆动长度增加  
                preDiff = curDiff; // 更新上一个差值为当前差值  
            }  
        }  
          
        // 返回摆动长度  
        return count;  
    }  
}

 要求删除元素使其达到最大摆动序列,应该删除什么元素呢?

 

局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值

整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。

实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了

在计算是否有峰值的时候,大家知道遍历的下标 i ,计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果prediff < 0 && curdiff > 0 或者 prediff > 0 && curdiff < 0 此时就有波动就需要统计。

这是我们思考本题的一个大题思路,但本题要考虑三种情况:

  1. 情况一:上下坡中有平坡
  2. 情况二:数组首尾两端
  3. 情况三:单调坡中有平坡

情况一:上下坡中有平坡

例如 [1,2,2,2,1]这样的数组,如图:

它的摇摆序列长度是多少呢? 其实是长度是 3,也就是我们在删除的时候 要不删除左面的三个 2,要不就删除右边的三个 2。

如图,可以统一规则,删除左边的三个 2:

在图中,当 i 指向第一个 2 的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个 2 的时候 prediff = 0 && curdiff < 0

如果我们采用,删左面三个 2 的规则,那么 当 prediff = 0 && curdiff < 0 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。

所以我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0),为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。

情况二:数组首尾两端

所以本题统计峰值的时候,数组最左面和最右面如何统计呢?

题目中说了,如果只有两个不同的元素,那摆动序列也是 2。

例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。

因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。

不写死的话,如何和我们的判断规则结合在一起呢?

可以假设,数组最前面还有一个数字,那这个数字应该是什么呢?

那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即 preDiff = 0(即将preDif初始化为0),如图:

376.摆动序列1

针对以上情形,result 初始为 1(默认最左面有一个峰值),此时 curDiff > 0 && preDiff <= 0,那么 result++(计算了左面的峰值),最后得到的 result 就是 2(峰值个数为 2 即摆动序列长度为 2)

情况三:单调坡度有平坡

在版本一中,我们忽略了一种情况,即 如果在一个单调坡度上有平坡,例如[1,2,2,2,3,4],如图:

图中,我们可以看出,版本一的代码在三个地方记录峰值,但其实结果因为是 2,因为 单调中的平坡 不能算峰值(即摆动)。

之所以版本一会出问题,是因为我们实时更新了 prediff。

那么我们应该什么时候更新 prediff 呢?

我们只需要在 这个坡度 摆动变化的时候,更新 prediff 就行,这样 prediff 在 单调区间有平坡的时候 就不会发生变化,造成我们的误判。

738.单调递增的数字 

738. 单调递增的数字

中等

提示

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。

示例 1:

输入: n = 10
输出: 9

示例 2:

输入: n = 1234
输出: 1234

示例 3:

输入: n = 332
输出: 299

提示:

  • 0 <= n <= 109

思路是在原来给出的数字中处理,从后向前遍历,如果遇到前一个数大于后一个数的情况,就将该前一个数减1,将后面的数字都改为9,这样既保持了递增,又使得最后的结果最大 

class Solution {  
    public int monotoneIncreasingDigits(int n) {  
        // 将整数n转换为字符串  
        String s = String.valueOf(n);  
        // 将字符串转换为字符数组,方便进行字符操作  
        char[] sChar = s.toCharArray();  
        // 初始化start为数组长度,表示还没有找到需要修改的位置  
        int start = sChar.length;  
          
        // 从数组倒数第二个字符开始向前遍历  
        for(int i = sChar.length - 2; i >= 0; i--){  
            // 如果当前字符大于下一个字符,说明不满足单调递增的条件  
            if(sChar[i] > sChar[i + 1]){  
                // 更新start为当前位置+1,表示从当前位置开始后面的字符都需要变为9  
                start = i + 1;  
                // 将当前字符减1,以便让后续字符满足单调递增的条件  
                sChar[i] -= 1;  
            }  
        }  
          
        // 从start位置开始,将后面的所有字符都变为'9',以满足单调递增的条件  
        for(int i = start; i < sChar.length; i++){  
            sChar[i] = '9';  
        }  
          
        // 将修改后的字符数组转换回整数  
        int num = Integer.parseInt(String.valueOf(sChar));  
        // 返回修改后的整数  
        return num;  
    }  
}

题目要求小于等于N的最大单调递增的整数,那么拿一个两位的数字来举例。

例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。

这一点如果想清楚了,这道题就好办了。

此时是从前向后遍历还是从后向前遍历呢?

从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。

这么说有点抽象,举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。

那么从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299

确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。

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

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

相关文章

植物病害识别:YOLO水稻病害识别数据集(11000多张,yolo标注)

YOLO水稻病害识别数据集&#xff0c;包含叶斑病&#xff0c;褐斑病&#xff0c;细菌性枯萎病&#xff0c;东格鲁病毒病4个常见病害类别&#xff0c;共11000多张图像&#xff0c;yolo标注完整&#xff0c;可直接训练。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c…

手机怎么剪辑音频?不可错过的6款音频剪辑好物

随着移动设备的普及和功能的日益强大&#xff0c;越来越多的人开始使用手机来创作和处理音频。无论你是音乐爱好者、播客还是视频制作者&#xff0c;一款优秀的音频剪辑应用都是不可或缺的。今天&#xff0c;就为大家推荐六款不可错过的手机音频剪辑好物。 1. 金舟音频大师 金…

STM32——FreeRTOS移植裸机外部中断不能使用原因

今天要在RTOS配置外部中断&#xff0c;为了省事&#xff0c;直接copy的裸机的外部中断例程&#xff0c;结果不能用&#xff0c;把可能出现的问题全部都查了一遍。 首先FreeRTOS可管理优先级是5~15&#xff0c;这个注意到了&#xff0c;但是还是不行。 是因为少了一个重要的参数…

数据库连接池-Durid连接池

数据库连接池是一个存放数据库连接的缓冲池&#xff0c;它能够管理和重用数据库连接&#xff0c;从而提高数据库访问的性能和效率。数据库连接是一种资源&#xff0c;它的创建和销毁是比较耗时的操作&#xff0c;因此使用连接池可以避免频繁地创建和销毁连接&#xff0c;从而减…

C++ 作业 24/3/11

1、提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数&#xff08;要求使用C风格字符串完成&#xff09; #include <iostream>using namespace std;int main() {string str;cout << "please enter str:&…

“离比特币减半还剩40天”!周期论到底是不是“刻舟求剑”?玄学还是现实?

作为周期论标志性重大事件&#xff0c;历史上的比特币减半似乎每每都能在市场上掀起风浪&#xff0c;但有一些人试图拿着放大镜抠细节&#xff0c;找出各种周期论地纰漏来试图打碎“比特币减半周期论”。那么“减半周期论”&#xff0c;到底是不是刻舟求剑&#xff1f; 事实上&…

RK3568驱动指南|第二篇 字符设备基础-第8章 驱动模块编译进内核实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

基于element-plus的Dialog选择控件

翻看之前工程师写的vue2的代码&#xff0c;很多都是复制、粘贴&#xff0c;也真是搞不懂&#xff0c;明明可以写一个控件&#xff0c;不就可以重复使用。很多前端总喜欢element搞一下&#xff0c;ant-design也搞一下&#xff0c;有啥意义&#xff0c;控件也不是自己写的&#x…

嵌入式Qt 标准对话框 - 颜色对话框QColorDialog-输入对话框QInputDialog

一.颜色对话框QColorDialog 颜色对话框使用&#xff1a; //构造颜色对话框对象 并指定父窗口 QColorDialog dlg(this);//设置颜色对话框的相关属性 dlg.setWindowTitle("Color Editor");//设置标题 dlg.setCurrenColor(Qt :: red);// 初始颜色//以模态方式打开颜色对…

自定义sql语句,但复杂的where部分由条件构造器wrapper来完成

我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。 步骤&#xff1a; 实现&#xff1a; Testvoid testCustomSqlUpdate(){//update tb_user set balance balance - #{amount} where id in(?,?,?,?,...)List<Long> ids …

0基础、适合转行学Python吗?

01 对于0基础的人&#xff0c;直接学 Python 编程合适吗&#xff1f; 在目前的编程语言中&#xff0c;Python的抽象程度是最高的&#xff0c;是最接近自然语言的&#xff0c;非常容易上手&#xff0c;Python 可以让你更好的理解编程这件事情。 所以&#xff0c;我只能说非常…

OpenHarmony教程—语言基础类库

介绍 本示例集合语言基础类库的各个子模块&#xff0c;展示了各个模块的基础功能&#xff0c;包含&#xff1a; ohos.buffer (Buffer)ohos.convertxml (xml转换JavaScript)ohos.process (获取进程相关的信息)ohos.taskpool (启动任务池)ohos.uri (URI字符串解析)ohos.url (UR…

高项--价值驱动的项目管理知识体系

说要参加软考已经过去两周了&#xff0c;到现在也没啥成果&#xff0c;今天决定还是动手记录小一些东西吧&#xff0c;也方便下次打开手机的时候可以查看记忆。总体上看可以分为三个部分&#xff1a;信息技术、项目管理、法律法规&#xff0c;而项目管理里面最终要的就是这个项…

R语言扩展包与MaxEnt模型的集成:实现高效的物种分布模拟

在生态学研究中&#xff0c;物种分布模拟是一项至关重要的任务。它有助于我们理解物种与环境之间的复杂关系&#xff0c;预测物种在气候变化或人类活动影响下的潜在分布变化。近年来&#xff0c;随着计算机技术的不断发展&#xff0c;基于机器学习的物种分布模拟方法逐渐成为研…

EasyExcel导出自定义表格

谈到新技术&#xff0c;每个人都会有点恐惧&#xff0c;怕处理不好。确实&#xff0c;第一次使用新技术会遇到很多坑&#xff0c;这次使用 EasyExcel 这个新技术去做 excel 导出&#xff0c;还要给表格加样式&#xff0c;遇到不同的版本问题&#xff0c;遇到颜色加错了地方&…

【Echarts】柱状图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

四川宏博蓬达法律咨询有限公司:专业可靠,您身边的法律守护者

在现代社会&#xff0c;法律咨询服务的需求日益增长&#xff0c;选择一家专业可靠的法律咨询公司成为了许多企业和个人的当务之急。四川宏博蓬达法律咨询有限公司便是这样一个值得信赖的法律服务提供者&#xff0c;以其专业、高效、贴心的服务&#xff0c;赢得了广大客户的信赖…

什么是Redis的数据分片?

Redis的数据分片(sharding)是一种将一个Redis数据集分割成多个部分&#xff0c;分别存诸在不同的Redis节点上的技术。它可以用于将一个单独的Redis数据库扩展到多个物理机器上&#xff0c;从而提高Redis集群的性能和可扩展性 Redis数据分片的实现方式通常是将数据按照某种规则(…

指令调用模板

也就是这边指令通过id和map会定位到一个结构体&#xff0c;然后这个结构再赋值两个成员&#xff0c;一个是函数一个是指令类型&#xff0c;然后这个函数是模板的实例化 使用的时候就传进去&#xff0c;这只是参数&#xff0c;最开始初始化的时候模板就已经实例化了。然后关于模…

Linux-网络编程报错分析

1【UDP】通信 【No route to host】&#xff1a;没有连接主机的路由 原因分析&#xff1a; 1.没有配置好默认网关地址&#xff0c;计算机上的路由表找不到到目标ip的路由。 解决方法&#xff1a;检查网络配置 2. 解决方法&#xff1a; 3. 解决方法&#xff1a;