map|动态规划|单调栈|LeetCode975:奇偶跳

作者推荐

【贪心算法】【中位贪心】.执行操作使频率分数最大

涉及知识点

单调栈 动态规划 map

题目

给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数。在你跳跃的过程中,第 1、3、5… 次跳跃称为奇数跳跃,而第 2、4、6… 次跳跃称为偶数跳跃。
你可以按以下方式从索引 i 向后跳转到索引 j(其中 i < j):
在进行奇数跳跃时(如,第 1,3,5… 次跳跃),你将会跳到索引 j,使得 A[i] <= A[j],A[j] 是可能的最小值。如果存在多个这样的索引 j,你只能跳到满足要求的最小索引 j 上。
在进行偶数跳跃时(如,第 2,4,6… 次跳跃),你将会跳到索引 j,使得 A[i] >= A[j],A[j] 是可能的最大值。如果存在多个这样的索引 j,你只能跳到满足要求的最小索引 j 上。
(对于某些索引 i,可能无法进行合乎要求的跳跃。)
如果从某一索引开始跳跃一定次数(可能是 0 次或多次),就可以到达数组的末尾(索引 A.length - 1),那么该索引就会被认为是好的起始索引。
返回好的起始索引的数量。
示例 1:
输入:[10,13,12,14,15]
输出:2
解释:
从起始索引 i = 0 出发,我们可以跳到 i = 2,(因为 A[2] 是 A[1],A[2],A[3],A[4] 中大于或等于 A[0] 的最小值),然后我们就无法继续跳下去了。
从起始索引 i = 1 和 i = 2 出发,我们可以跳到 i = 3,然后我们就无法继续跳下去了。
从起始索引 i = 3 出发,我们可以跳到 i = 4,到达数组末尾。
从起始索引 i = 4 出发,我们已经到达数组末尾。
总之,我们可以从 2 个不同的起始索引(i = 3, i = 4)出发,通过一定数量的跳跃到达数组末尾。
示例 2:
输入:[2,3,1,1,4]
输出:3
解释:
从起始索引 i=0 出发,我们依次可以跳到 i = 1,i = 2,i = 3:
在我们的第一次跳跃(奇数)中,我们先跳到 i = 1,因为 A[1] 是(A[1],A[2],A[3],A[4])中大于或等于 A[0] 的最小值。
在我们的第二次跳跃(偶数)中,我们从 i = 1 跳到 i = 2,因为 A[2] 是(A[2],A[3],A[4])中小于或等于 A[1] 的最大值。A[3] 也是最大的值,但 2 是一个较小的索引,所以我们只能跳到 i = 2,而不能跳到 i = 3。
在我们的第三次跳跃(奇数)中,我们从 i = 2 跳到 i = 3,因为 A[3] 是(A[3],A[4])中大于或等于 A[2] 的最小值。
我们不能从 i = 3 跳到 i = 4,所以起始索引 i = 0 不是好的起始索引。
类似地,我们可以推断:
从起始索引 i = 1 出发, 我们跳到 i = 4,这样我们就到达数组末尾。
从起始索引 i = 2 出发, 我们跳到 i = 3,然后我们就不能再跳了。
从起始索引 i = 3 出发, 我们跳到 i = 4,这样我们就到达数组末尾。
从起始索引 i = 4 出发,我们已经到达数组末尾。
总之,我们可以从 3 个不同的起始索引(i = 1, i = 3, i = 4)出发,通过一定数量的跳跃到达数组末尾。
示例 3:
输入:[5,1,3,4,2]
输出:3
解释:
我们可以从起始索引 1,2,4 出发到达数组末尾。
提示:
1 <= A.length <= 20000
0 <= A[i] < 100000

代码

单调栈

此方法比map巧妙,性能差不多,值得学习。时间复杂度:O(nlogn)。

变量函数解析

indexs计算奇数跳时,arr[index[i]] 升序,且相等的元素,相对顺序不变。计算偶数跳时,arr[index[i]] 降序,且相等的元素,相对顺序不变。
Next计算奇(偶)数跳的下一个位置,如果无法跳,则值为m_c
vStatus记录偶数(奇数)跳能否跳到队尾。vStatus[0][m_c]和vStatus[0][m_c]为false,避免处理边界条件

Next奇数跳为例

令j=index[jj],按jj从小到的顺序,将j入栈,由于arr[index[jj]]是升序,所以:规则一:arr[栈中元素] <=arr[j]。
(sta.top() < j 成立,说明:
规则二:j在sta.top()右边。
规则三:令index[jj2] 为sta.top(),arr[index(jj2,j)]中的数(即大于等于arr[sta.top()] 同时小于等于arr[j]的数)全部在sta.top()的左边,否则出栈了。
结合规则一二三,stat.top()的下一步就是j。

核心代码

class Solution {
public:int oddEvenJumps(vector<int>& arr) {m_c = arr.size();vector<int> indexs(m_c);iota(indexs.begin(), indexs.end(), 0);sort(indexs.begin(), indexs.end(), [&](const int i1, const int i2) {return (arr[i1] < arr[i2]) || ((arr[i1] == arr[i2]) && (i1 < i2)); });const auto& v1 = Next(indexs);sort(indexs.begin(), indexs.end(), [&](const int i1, const int i2) {return (arr[i1] > arr[i2]) || ((arr[i1] == arr[i2]) && (i1 < i2)); });const auto& v2 = Next(indexs);vector<vector<bool>> vStatus(2, vector<bool>(m_c+1));int iRet = 1;vStatus[0][m_c-1] = true;vStatus[1][m_c - 1] = true;for (int i = m_c - 1 - 1; i >= 0; i--){vStatus[0][i] = vStatus[1][v2[i]];//偶数跳vStatus[1][i] = vStatus[0][v1[i]];//奇数跳iRet +=  (int)vStatus[1][i];}return iRet;}vector<int> Next(const vector<int>& indexs){vector<int> vNext(indexs.size(), indexs.size());stack<int> sta;for (int j : indexs){while (sta.size() && (sta.top() < j)){vNext[sta.top()] = j;sta.pop();}sta.emplace(j);}return vNext;}int m_c;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}
}int main()
{vector<int> arr;{Solution slu;arr = { 10,13,12,14,15 };auto res = slu.oddEvenJumps(arr);Assert(2, res);}{Solution slu;arr = { 2,3,1,1,4 };auto res = slu.oddEvenJumps(arr);Assert(3, res);}{Solution slu;arr = { 5,1,3,4,2 };auto res = slu.oddEvenJumps(arr);Assert(3, res);}//CConsole::Out(res);
}

2023年3月版:map

利用map性能和单调栈差不多,好理解。从后向前遍历各元素,map的键对应arr[i],map的值对应i。如果arr[i],i小的(后加入的)覆盖前面的。
时间复杂度:O(nlogn)。

map

map可以分成有序(单调)map和无序(哈希)map。还可分成单键map和多键map(允许重复的键)。

 class Solution {public:int oddEvenJumps(vector<int>& arr) {vector<vector<bool>> result;result.assign(arr.size(), vector<bool>(2));result[arr.size() - 1][0] = true;result[arr.size() - 1][1] = true;std::map<int, int> mValueIndex;mValueIndex[arr.back()] = arr.size()-1;for (int i = arr.size() - 2; i >= 0; i--){{//奇数跳跃auto it = mValueIndex.lower_bound(arr[i]);if (mValueIndex.end() != it){result[i][0] = result[it->second][1];}}{//偶数跳跃auto it2 = mValueIndex.upper_bound(arr[i]);if (mValueIndex.begin() != it2){--it2;result[i][1] = result[it2->second][0];}mValueIndex[arr[i]] = i;}}int iNum = 0;for (int i = 0; i < arr.size(); i++){if (result[i][0]){iNum++;}}return iNum;}};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法C++ 实现。

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

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

相关文章

linux 驱动——私有数据

文章目录 linux 驱动中的私有数据container_of驱动程序应用程序模块使用 linux 驱动中的私有数据 container_of 参考&#xff1a;linux——宏 list_entry/container_of 驱动程序 #include "linux/device/class.h" #include "linux/export.h" #include…

Python人脸识别

实现效果 代码 import cv2# 加载人脸识别分类器 face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml)# 打开摄像头 cap cv2.VideoCapture(0)while True:# 读取摄像头捕获的帧ret, frame cap.read()# 将帧转换为灰度图像gray cv2.cvtColor(frame, c…

迪文屏开发保姆级教程——页面键盘

迪文屏页面键盘保姆级教程。 本篇文章主要介绍了在DGBUS平台上使用页面键盘的步骤。 迪文屏官方开发指南PDF&#xff1a;&#xff08;不方便下载的私聊我发给你&#xff09; https://download.csdn.net/download/qq_21370051/88647174?spm1001.2014.3001.5503https://downloa…

vivado 关于时钟

关于时钟 在数字设计中&#xff0c;时钟代表了从寄存器可靠传输数据的时间基准注册。AMD Vivado™集成设计环境&#xff08;IDE&#xff09;计时引擎使用时钟计算时序路径要求并通过以下方式报告设计时序裕度的特性松弛计算的方法有关更多信息&#xff0c;请参阅Vivado Design…

AI百模大战:引领行业变革与开启人才黄金时代

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux学习 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 技术进步&#xff1a;AI的飞速发展 1. 深度学习的多领域应用 2. 自然语言处理的语境理解提升 3. 计算机视觉的实时处理能力提高 4…

Python学习笔记(六):函数的多返回值、函数的多种参数使用形式、匿名函数、文件的读取操作、文件的写入 、文件的追加

目录 一、函数的多返回值 二、函数的多种参数使用形式 2.1位置参数 2.2关键字参数 2.3缺省参数 2.4不定长参数 三、匿名函数 3.1 函数作为参数传递 3.2 函数的定义 3.3 匿名函数定义语法&#xff1a; 四、文件的读取操作 4.1 open&#xff08;&#xff09;打开函数…

图卷积神经网络发展

1. 图神经网络&#xff08;GNN&#xff09; 图神经网络的概念最早在2005年提出。2009年Franco博士在其论文 [2]中定义了图神经网络的理论基础。 本文中所提到的图均指图论中的图(Graph)。它是一种由若干个结点(Node)及连接两个结点的边(Edge)所构成的图形&#xff0c;用于刻画…

【模式识别】解锁降维奥秘:深度剖析PCA人脸识别技术

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《模式之谜 | 数据奇迹解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1f30c;1 初识模式识…

智能化物联网(IoT):发展、问题与未来前景

导言 智能化物联网&#xff08;IoT&#xff09;作为信息技术领域的一项核心技术&#xff0c;正在深刻改变人们的生活和工作方式。本文将深入研究IoT的发展过程、遇到的问题及解决过程、未来的可用范围&#xff0c;以及在各国的应用和未来的研究趋势。探讨在哪些方面能够取得胜利…

k8s-ingress特性 9

TLS加密 创建证书 测试访问 auth认证 创建认证文件 rewrite重定向 进入域名时&#xff0c;会自动重定向到hostname.html 示例&#xff1a; 测试 版本的升级迭代&#xff0c;之前利用控制器进行滚动更新&#xff0c;在升级过程中无法做到快速回滚 更加平滑的升级&#xff1…

【数据结构】线段树算法总结(区间修改)

知识概览 线段树一般有5个操作&#xff1a; pushup&#xff1a;用子节点更新当前节点信息pushdown&#xff1a;把懒标记往下传build&#xff1a;初始化一棵树modify&#xff1a;修改一个区间query&#xff1a;查询一个区间 不带懒标记&#xff08;支持单点修改&#xff09;的线…

Mysql-干净卸载教程

卸载 服务停掉 先把mysql服务停掉&#xff0c;如下点击右键&#xff0c;停止运行。 删除C盘内文件 接下来c盘里面的三个文件下的MySQL一一删除&#xff0c;需要注意的是 需要注意的是programdata文件下可能 隐藏了MySQL文件&#xff0c;所以可以在查看选项显示隐藏的文件。 …

PolarDB-X、OceanBase、CockroachDB、TiDB二级索引写入性能测评

为什么要做这个测试 二级索引是关系型数据库相较于NoSQL数据库的一个关键差异。二级索引必须是强一致的&#xff0c;因此索引的写入需要与主键的写入放在一个事务当中&#xff0c;事务的性能是二级索引性能的基础。 目前市面上的分布式数据库中&#xff0c;从使用体验的角度看…

前后端分离下的鸿鹄电子招投标系统:使用Spring Boot、Mybatis、Redis和Layui实现源码与立项流程

在数字化时代&#xff0c;采购管理也正经历着前所未有的变革。全过程数字化采购管理成为了企业追求高效、透明和规范的关键。该系统通过Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;打造了从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通过…

argmin与argmax

argmin 是一个数学术语&#xff0c;用于表示一个函数在其定义域中取得最小值的参数值&#xff08;自变量的值&#xff09;&#xff0c;而不是最小值本身。 具体来说&#xff0c;argmin 表示函数的自变量&#xff08;通常是一个实数或向量&#xff09;&#xff0c;当输入到该函数…

JavaWeb笔记之前端开发JavaScript

一、引言 1.1 简介 JavaScript一种解释性脚本语言&#xff0c;是一种动态类型、弱类型、基于原型继承的语言&#xff0c;内置支持类型。 它的解释器被称为JavaScript引擎&#xff0c;作为浏览器的一部分&#xff0c;广泛用于客户端的脚本语言&#xff0c;用来给HTML网页增加…

统计个数并调用--函数设计与实现

#定义函数 count(s) ,统计字符串中小写字母、大写字母、数字的个数&#xff0c;并以字典为结果返回给调用函数。 # (1)判断字符类型 def count(s):#创建字典&#xff0c;用于保存变量dictionary {数字: 0, 小写字母: 0, 大写字母: 0, 其他字符: 0}for c in s:if c.isdigit():d…

React学习计划-React16--React基础(三)收集表单数据、高阶函数柯里化、类的复习

1. 收集表单数据 包含表单的组件分类 受控组件——页面中所有输入类的DOM,随着输入&#xff0c;把值存维护在状态里&#xff0c;需要用的时候去状态里取值&#xff08;推荐&#xff0c;避免了过渡使用ref&#xff09;非受控组件——页面中所有输入类的DOM&#xff0c;现用现取…

Java 并发编程 —— Fork/Join 框架的原理详解

目录 一. 前言 二. 并发和并行 2.1. 并发 2.2. 并行 2.3. 分治法 三. ForkJoin 并行处理框架的理论 3.1. ForkJoin 框架概述 3.2. ForkJoin 框架原理 3.3. 工作窃取算法 四. ForkJoin 并行处理框架的实现 4.1. ForkJoinPool 类 4.2. ForkJoinWorkerThread 类 4.3.…

MongoDB的原子操作findAndModify和findOneAndUpdate

本文主要介绍MongoDB的原子操作findAndModify和findOneAndUpdate。 目录 MongoDB的原子操作一、findAndModify二、findOneAndUpdate MongoDB的原子操作 MongoDB的原子操作指的是在单个操作中对数据库的数据进行读取和修改&#xff0c;并确保操作是原子的&#xff0c;即要么完全…