【单调栈 】2289. 使数组按非递减顺序排列

news2024/12/23 0:50:03

本文涉及的基础知识点

单调栈分类、封装和总结

LeetCode2289. 使数组按非递减顺序排列

给你一个下标从 0 开始的整数数组 nums 。在一步操作中,移除所有满足 nums[i - 1] > nums[i] 的 nums[i] ,其中 0 < i < nums.length 。
重复执行步骤,直到 nums 变为 非递减 数组,返回所需执行的操作数。
示例 1:
输入:nums = [5,3,4,4,7,3,6,11,8,5,11]
输出:3
解释:执行下述几个步骤:

  • 步骤 1 :[5,3,4,4,7,3,6,11,8,5,11] 变为 [5,4,4,7,6,11,11]
  • 步骤 2 :[5,4,4,7,6,11,11] 变为 [5,4,7,11,11]
  • 步骤 3 :[5,4,7,11,11] 变为 [5,7,11,11]
    [5,7,11,11] 是一个非递减数组,因此,返回 3 。
    示例 2:
    输入:nums = [4,5,7,7,13]
    输出:0
    解释:nums 已经是一个非递减数组,因此,返回 0 。
    提示:
    1 <= nums.length <= 105
    1 <= nums[i] <= 109

单调栈

∀ \forall i,j ,i < j ,且nums[i] > nums[j] 则nums[j]必定被删除。性质一,下面来证明:
如果有多个符合的i,取最大的。 即 ∀ k ∈ ( i , j ) \forall k \in (i,j) k(i,j) nums[k] <= nums[j] ,即:nums[i]会删除所有nums[k]后,再删除nums[j]。
会不会存在如下情况:nums[i]被nums[m]删除,会。但nums[j]会被nums[m]删除。
如果nums[i]没有被删除,则nums[j]需要j-i次删除。
如果nums[i]被删除,也是。假设i删除k1的同时被删除,此是m在k1的位置;如果nums[i]没被删除,此刻i也在k1位置。
j从小到大枚举nums[j],栈sta记录 nums[0…j-1]的值和下标。
寻找i的逻辑:大于nums[j]且下标最大。那值小于等于nums[j],且下标小于j的被淘汰。淘汰后:
一,下标升序。
二,值降序。
三,栈中所有值大于nums[j]
如果栈非空:nums[j]需要删除 j - sta.top().second
取最大值,如果 ∀ j \forall j j的栈都为空,则结果为0

思路错误

15 2 13 1 可以同时删除,15删除2时,13删除1。
错误代码

class Solution {
public:
	int totalSteps(vector<int>& nums) {
		stack<pair<int, int>> sta;
		int ret = 0;
		for (int j = 0; j < nums.size(); j++) {
			while (sta.size() && (sta.top().first <= nums[j])) {
				sta.pop();
			}
			if (sta.size()) {
				ret = max(ret, j - sta.top().second);
			}
			sta.emplace(nums[j], j);
		}
		return ret;
	}
};

换个错误的思路

如果不存在i,ret[j]为0。
如果nums[i-1] > nums[i] ret[i]为1。
否则 ret[i] = ret[i-1]。
错误原因:num[m1] 删除nums[i-1] 因为小于等于nums[i] 无法删除nums[i]

class Solution {
public:
	int totalSteps(vector<int>& nums) {
		stack<tuple<int, int,int>> sta;
		vector<int> ret;
		for (int j = 0; j < nums.size(); j++) {
			while (sta.size() && (get<0>(sta.top()) <= nums[j])) {
				sta.pop();	
			}
			if (sta.size()) {
				if (nums[j - 1] > nums[j]) {
					ret.emplace_back(1);
				}
				else {
					ret.emplace_back(ret.back() + 1);
				}
			}
			else {
				ret.emplace_back(0);
			}
			sta.emplace(nums[j], j,0);
		}
		return *  std::max_element(ret.begin(), ret.end());
	}
};

正确思路

如果是nums[m2]删除nums[m1],且nums[m2]>nums[i],则ret[i] = ret[m1]+1否则:
由于是nums[m3]删除nums[m1],且nums[m3]> nums[i] 故vet[i] >= ret[m2]+1,否则:
⋮ \vdots
我们只需要求m1 … m2等的最大值。
我们假定nums[j]被nums[i]所删除,则:在nums[j]被删除前,nums[i+1…j-1]都已经被删除。
ret[j]一定等于 ret[i+1…j-1]的最大值+1。
令 i < k1 <k2 < j。 如果nums[k1]被 nums[k2]淘汰,不影响最终结果。因为:
因为nums[k1]无法淘汰nums[k2],nums[m]淘汰nums[k2]必须先淘汰nums[k1],故ret[k1] 一定小于ret[k2]

代码

class Solution {
public:
	int totalSteps(vector<int>& nums) {
		stack<pair<int,int>> sta;
		int ret = 0;
		for (int j = 0; j < nums.size(); j++) {
			int iMax = 0;
			while (sta.size() && (sta.top().first <= nums[j])) {
				iMax = max(iMax, sta.top().second);
				sta.pop();	
			}
			int cnt = sta.empty() ? 0 : (iMax + 1);		
			ret = max(ret, cnt);
			sta.emplace(nums[j],cnt);
		}
		return ret;
	}
};

单元测试

template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{
	Assert::AreEqual(t1, t2);
}
void AssertEx( double t1,  double t2)
{
	auto str = std::to_wstring(t1) + std::wstring(1,32) + std::to_wstring(t2);
	Assert::IsTrue(abs(t1 - t2) < 1e-5,str.c_str() );
}

template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
	Assert::AreEqual(v1.size(), v2.size());
	for (int i = 0; i < v1.size(); i++)
	{
		Assert::AreEqual(v1[i], v2[i]);
	}
}

template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
	sort(vv1.begin(), vv1.end());
	sort(vv2.begin(), vv2.end());
	Assert::AreEqual(vv1.size(), vv2.size());
	for (int i = 0; i < vv1.size(); i++)
	{
		AssertEx(vv1[i], vv2[i]);
	}
}

namespace UnitTest
{
	vector<int> nums;
	TEST_CLASS(UnitTest)
	{
	public:
		TEST_METHOD(TestMethod00)
		{
			nums = { 5, 3, 4, 4, 7, 3, 6, 11, 8, 5, 11 };
			auto res = Solution().totalSteps(nums);
			AssertEx(3, res);
		}
		TEST_METHOD(TestMethod01)
		{
			nums = { 4,5,7,7,13 };
			auto res = Solution().totalSteps(nums);
			AssertEx(0, res);
		}
		TEST_METHOD(TestMethod02)
		{
			nums = { 5,14,15,2,11,5,13,15 };
			auto res = Solution().totalSteps(nums);
			AssertEx(3, res);
		}
		TEST_METHOD(TestMethod03)
		{
			nums = { 7,14,4,14,13,2,6,13 };
			auto res = Solution().totalSteps(nums);
			AssertEx(3, res);
		}
		TEST_METHOD(TestMethod04)
		{
			nums = { 10,1,2,3,4,5,6,1,2,3 };
			auto res = Solution().totalSteps(nums);
			AssertEx(6, res);
		}
	};
}

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

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

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

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

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

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

相关文章

【重磅推荐】《一本书读懂大模型:技术创新、商业应用与产业变革》发布!大模型零基础入门到精通

近日&#xff0c;由中国电信研究院天翼智库大模型研究团队编写、中国电信集团科技委主任邵广禄倾情作序的**《一本书读懂大模型&#xff1a;技术创新、商业应用与产业变革》**正式出版。本书系统介绍了大模型技术的发展历程、核心技术、行业应用、产业体系、治理问题以及未来展…

DeFi 发展的岔路口,Pencils Protocol带领投资者们“向前看”

DeFi 市场是否还存在 Alpha 机会&#xff1f; 走下坡路的 DeFi 去中心化金融&#xff08;DeFi&#xff09;曾是区块链世界发展的起点&#xff0c;也是链上世界流动性的重要支柱。然而&#xff0c;自 2021 年 DeFi 领域的总锁仓量&#xff08;TVL&#xff09;达到历史巅峰——…

模型压缩之剪枝

&#xff08;1&#xff09;通道选择 这里要先解释一下&#xff1a; &#xff08;1&#xff09;通道剪枝 那我们实际做法不是上面直接对所有层都添加L1正则项&#xff0c;而是仅仅对BN层权重添加L1正则项。通道剪枝具体步骤如下&#xff1a; 1.BN层权重添加L1正则项&#xf…

ElementUI实现el-table组件的合并行功能

前言 有时遇到一些需求&#xff0c;需要实现ElementUI中&#xff0c;el-tabled组件合并单元格的功能&#xff0c;稍微了解一下它的数据格式&#xff0c;不难可以写出比合并方法。但是在鼠标经过单元行时&#xff0c;会出现高亮的行与鼠标经过的行不一致的BUG。因此还需要实现c…

超级右键 - 为 Mac 的右键菜单升级一下

是不是有很多小伙伴&#xff0c;希望 Mac 也能像 Windows 一样&#xff0c;拥有丰富的右键菜单&#xff0c;快速完成新建、剪切、发送文件等操作。 一个叫作超级右键的工具就能做到&#xff0c;它能为 Mac 右键菜单增添多个功能选项&#xff0c;如 Win 系统般一键新建 / 剪切文…

vue通过html2canvas+jspdf生成PDF问题全解(水印,分页,截断,多页,黑屏,空白,附源码)

前端导出PDF的方法不多&#xff0c;常见的就是利用canvas画布渲染&#xff0c;再结合jspdf导出PDF文件&#xff0c;代码也不复杂&#xff0c;网上的代码基本都可以拿来即用。 如果不是特别追求完美的情况下&#xff0c;或者导出PDF内容单页的话&#xff0c;那么基本上也就满足业…

我的大模型岗位面试总结!太卷了!!!—我面试了24家大模型岗位 只拿了9个offer!

这段时间面试了很多家&#xff08;共24家&#xff0c;9个offer&#xff0c;简历拒了4家&#xff0c;剩下是面试后拒的&#xff09;&#xff0c;也学到了超级多东西。 大模型这方向真的卷&#xff0c;面试时好多新模型&#xff0c;新paper疯狂出&#xff0c;东西出的比我读的快…

传统CV算法——基于opencv的答题卡识别判卷系统

基于OpenCV的答题卡识别系统&#xff0c;其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术&#xff0c;自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述&#xff1a; 1. 导入必要的库 系统首先导入…

误删的PPT怎么恢复回来?

在日常工作和学习中&#xff0c;PPT已成为我们不可或缺的工具。然而&#xff0c;有时不小心误删重要的PPT文件&#xff0c;可能会让人倍感焦虑。别担心&#xff0c;本文将为你提供几种实用的方法&#xff0c;帮助你轻松恢复误删的PPT文件。 一、从回收站恢复 当你误删文件时&…

【Grafana】Prometheus结合Grafana打造智能监控可视化平台

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

香港一带一路研究院国际事务研究中心副主任陈景才阐述香港在一带一路建设及区块链金融领域的关键作用

2024年8月28日&#xff0c;香港金管局举行Ensemble项目沙盒&#xff08;以下简称沙盒&#xff09;启动仪式&#xff0c;并宣布首阶段试验将涵盖四大代币化资产用例主题&#xff0c;标志着金融业在代币化技术的实际应用进程中迈出重要一步。香港一带一路研究院国际事务研究中心副…

解剖学上合理的分割:通过先验变形显式保持拓扑结构|文献速递--基于深度学习的医学影像病灶分割

Title 题目 Anatomically plausible segmentations: Explicitly preserving topology through prior deformations 解剖学上合理的分割&#xff1a;通过先验变形显式保持拓扑结构 01 文献速递介绍 进行环向应变或壁厚度的计算&#xff0c;这些测量通常用于诊断肥厚性心肌病…

IDEA 安装lombok插件不兼容的问题及解决方法

解决&#xff1a;IDEA 安装lombok插件不兼容问题&#xff0c;plugin xxxx is incompatible 一、去官网下载最新的2024版本 地址传送通道&#xff1a; lombok插件官网地址https://plugins.jetbrains.com/plugin/6317-lombok/versions/stable 二、修改参数的配置 在压缩包路径…

理解C++的【内部链接】和【外部链接】

一、前言 最近在看《大规模C程序设计》一书&#xff0c;看第一章关于内部链接和外部链接这部分时&#xff0c;有点不太明白。通过书本理解和网上查阅文献&#xff0c;在此记录一下自己对这部分知识点的理解。 首先&#xff0c;提几个问题&#xff1a; 什么是内部链接&#x…

全域运营公司哪家做得好?全域运营系统综合评测结果揭晓!

作为当前火爆的风口项目&#xff0c;一直以来&#xff0c;全域运营都以其广阔的业务范围和巨大的收益潜力吸引着一批又一批的创业者入局分羹&#xff0c;使得全域运营公司哪家做得好等问题一度成为了相关创业者交流群内的讨论重点。 从目前的市场情况来看&#xff0c;由于进入…

定期加强医疗器械维修技能学习重要性

医学影像技术是现代医疗的重要支撑,是辅助临床诊断和治疗不可或缺的技术手段。影像医疗设备成像质量的优劣程度在一定程度上决定了疾病诊断结果的准确性,而术中使用的影像设备的优劣甚至可能影响手术的成功率。因此保证设备正常使用是重中之重&#xff0c;设备售后维修保养也就…

Langchain-Chatchat+Qwen实现本地知识库

1.基础介绍 Langchain-Chatchat一种利用 langchain 思想实现的基于本地知识库的问答应用&#xff0c;目标期望建立一套对中文场景与开源模型支持友好、可离线运行的知识库问答解决方案。大致过程包括加载文件 -> 读取文本 -> 文本分割 -> 文本向量化 -> 问句向量化…

《OpenCV计算机视觉》—— 对图片的各种操作

文章目录 1、安装OpenCV库2、读取、显示、查看图片3、对图片进行切割4、改变图像的大小5、图片打码6、图片组合7、图像运算8、图像加权运算 1、安装OpenCV库 使用pip是最简单、最快捷的安装方式 pip install opencv-python3.4.2还需要安装一个包含了其他一些图像处理算法函数的…

vector中的push_back()和emplace_back()的区别、以及使用场景

目录 前言 1. 基本区别 2. 性能差异 3. 构造参数传递 4. 使用场景总结 前言 push_back() 更适合在已经有对象实例的情况下使用。emplace_back() 则更适合需要在容器内部直接构造对象的场景&#xff0c;特别是在性能敏感的情况下。 1. 基本区别 push_back(): 作用&#xff…

酒店智能触摸开关在酒店管理中的作用

在众多智能化设备中&#xff0c;酒店智能触摸开关以其便捷性、高效性和节能环保的特性&#xff0c;正逐步成为提升住客体验、优化酒店运营管理的关键元素。本文将深入探讨酒店智能触摸开关在酒店管理中的多重作用。 一、提升住客体验&#xff0c;增强服务品质 便捷操作&#xf…