【动态规划-最长递增子序列(LIS)】【hard】力扣1671. 得到山形数组的最少删除次数

ops/2024/10/21 4:13:58/

我们定义 arr 是 山形数组 当且仅当它满足:

arr.length >= 3
存在某个下标 i (从 0 开始) 满足 0 < i < arr.length - 1 且:
arr[0] < arr[1] < … < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > … > arr[arr.length - 1]
给你整数数组 nums​ ,请你返回将 nums 变成 山形状数组 的​ 最少 删除次数。

示例 1:
输入:nums = [1,3,1]
输出:0
解释:数组本身就是山形数组,所以我们不需要删除任何元素。

示例 2:
输入:nums = [2,1,1,5,6,2,3,1]
输出:3
解释:一种方法是将下标为 0,1 和 5 的元素删除,剩余元素为 [1,5,6,3,1] ,是山形数组。

在这里插入图片描述

二分查找

class Solution {
public:int minimumMountainRemovals(vector<int>& nums) {int n = nums.size();vector<int> lis(n, 1), lds(n, 1);vector<int> inc; for (int i = 0; i < n; ++i) {auto it = lower_bound(inc.begin(), inc.end(), nums[i]);if (it == inc.end()) {inc.push_back(nums[i]);} else {*it = nums[i];}lis[i] = inc.size();}vector<int> dec; // 计算从右到左的最长递减子序列 (LDS) 长度,使用二分查找for (int i = n - 1; i >= 0; --i) {auto it = lower_bound(dec.begin(), dec.end(), nums[i]);if (it == dec.end()) {dec.push_back(nums[i]);} else {*it = nums[i];}lds[i] = dec.size();}int minRemovals = n;for (int i = 1; i < n - 1; ++i) {if (lis[i] > 1 && lds[i] > 1) {// 山峰的长度是 lis[i] + lds[i] - 1minRemovals = min(minRemovals, n - (lis[i] + lds[i] - 1));}}return minRemovals;}
};

时间复杂度:O(nlogn),其中 n 是数组 nums 的长度。

空间复杂度:O(n)。

这道题的思路就是构建一个最长递增子序列LIS和最长递减子序列LDS。
开始,我们定义vector<int> lis(n, 1), lds(n, 1);来储存以nums[i]结尾的最长递增/递减子序列长度。

我们定义一个迭代器it,指向通过二分查找找到的inc数组中的大于等于nums[i]的元素。
需要注意是
由于 upper_bound 查找的是严格大于当前值的元素,它确保了序列是非严格递增的,即允许相同的元素出现在序列中。例如,如果当前序列为 1, 2, 3,新加入的元素也是 3,upper_bound 会找到序列末尾并在适当位置插入新的 3,从而维持非严格递增的性质。

而lower_bound查找的是大于等于nums[i]的元素,所以nums[i]如果有与inc中相等的元素,会替换而不是推入,这保证了最长递增子序列是严格递增的。

我们还定义了lis和lds来储存不同nums[i]结尾的最长递增。递减子序列的长度。我们遍历每个元素结尾的最长递增子序列和最长递减子序列的长度。·然后通过minRemovals来记录山峰数组的最少删除次数。

最后返回minRemovals。


http://www.ppmy.cn/ops/125475.html

相关文章

手机解锁如何工作?解锁手机的顶级应用程序

解锁手机软件是指用于解锁特定运营商或网络的手机的计算机程序或工具&#xff0c;使其能够与其他运营商一起使用或在国际上使用。 当个人想要切换到不同的网络提供商或在国外旅行时使用其设备时&#xff0c;通常会使用此软件。以下是解锁手机软件的概述&#xff1a;需要注意的…

Java List 的介绍与实现原理

什么是 List 在 Java 中&#xff0c;List 是一种有序集合&#xff0c;允许重复的元素。它是 Java Collections Framework 的一部分&#xff0c;提供了一种便捷的方式来存储和操作线性数据。常见的实现类包括 ArrayList、LinkedList 和 Vector。 实现原理 1. ArrayList Arra…

selenium有多个frame页时的操作方法(5)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.frame()可以切换到不同的frame页然后才再定位某个元素做一些输入/点击等操作。 比如下面这个测试网站有2个frame页&#xff1a;http://www.sahitest.com/demo/framesTest.h…

docker详解介绍+基础操作 (四)容器镜像

一.镜像结构和原理 Docker 镜像是 Docker 技术的核心组成部分之一&#xff0c;它用于封装应用程序及其依赖项&#xff0c;以便在任何支持 Docker 的环境中运行。了解 Docker 镜像的结构和原理对于有效使用 Docker 至关重要。以下是对 Docker 镜像结构和原理的详细介绍。 Dock…

开放式耳机咋选?开放式蓝牙耳机排行榜五强推荐推荐

​在当今的耳机市场上&#xff0c;开放式耳机因其时尚的外观和舒适的佩戴体验&#xff0c;已经成为广受欢迎的日常选择。然而&#xff0c;面对众多品牌和参差不齐的质量&#xff0c;选择一款合适的开放式耳机确实让人头疼。作为一名拥有三年耳机评测经验的博主&#xff0c;同时…

2024系统分析师考试---数据仓库相关概念

前言&#xff1a; 传统的操作型数据库主要面向业务的&#xff0c;所执行的操作基本上也是联机事务处理&#xff0c;随着企业规模的增长&#xff0c;历史积累的数据越来越多&#xff0c;如何利用历史数据来为未来决策服务&#xff0c;就显得越来越重要了&#xff0c;而数据仓库就…

系统架构师备考记忆不太清楚的点-信息系统-需求分析

霍尔三维结构 逻辑维&#xff1a;解决问题的逻辑过程 过程有明确问题、确立目标、系统综合、系统分析、优化、系统决策、实施计划 时间维&#xff1a;工作进度 这个纬度则是做工作计划的输出 有 规划阶段、拟定方案、研制阶段、生产阶段、安装阶段、运行阶段、更新阶段 知…

golang语法

参考链接&#xff1a;https://www.runoob.com/go/ 创建变量 // 3种方法 var a int a : 10 // 类型推断 a : make() // 复合类型循环 // 3种循环 for i : 0; i < 10; i {// 循环体} // 传统for循环 for index, num : range nums {// 循环体} // nums是可迭代的复合类型…