得到山形数组的最少删除次数(LeetCode日记)

2023-12-23 14:20

本文主要是介绍得到山形数组的最少删除次数(LeetCode日记),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LeetCode-1671-得到山形数组的最少删除次数

题目信息:

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

  • a r r . l e n g t h > = 3 arr.length >= 3 arr.length>=3
  • 存在某个下标 i i i (从 0 开始) 满足 0 < i < a r r . l e n g t h − 1 0 < i < arr.length - 1 0<i<arr.length1 且:
    • a r r [ 0 ] < a r r [ 1 ] < . . . < a r r [ i − 1 ] < a r r [ i ] arr[0] < arr[1] < ... < arr[i - 1] < arr[i] arr[0]<arr[1]<...<arr[i1]<arr[i]
    • a r r [ i ] > a r r [ i + 1 ] > . . . > a r r [ a r r . l e n g t h − 1 ] arr[i] > arr[i + 1] > ... > arr[arr.length - 1] arr[i]>arr[i+1]>...>arr[arr.length1]

给你整数数组 n u m s nums nums​ ,请你返回将 n u m s 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] ,是山形数组。

提示:

  • 3 <= nums.length <= 1000
  • 1 <= nums[i] <= 109
  • 题目保证 nums 删除一些元素后一定能得到山形数组。

相关标签 :动态规划,二分查找

题解

这道题实际上是 Leetcode 第300题 最长递增子序列 的 扩展问题。建议大家在做这道题之前可以先去了解一下上面这道题的思路和代码。下面我们开始分析本题。

方法 : 动态规划
根据题目的要求,我们需要使用最少的删除次数,使得给定的数组 n u m s nums nums 成为 山形状数组。这等价于,我们需要找出数组 n u m s nums nums 的一个最长的子序列,并且这个子序列是一个山形状数组
因此,我们可以考虑枚举山形状数组的最高点。记数组 n u m s nums nums 的长度为 n n n,并且枚举第 i i i 个元素 n u m s [ i ] nums[i] nums[i] 作为最高点,那么:

  • ( 1 ) (1) (1)在数组的前缀部分 n u m s [ 0.. i ] nums[0..i] nums[0..i] ,找出一个严格递增的子序列,并且以 n u m s [ i ] nums[i] nums[i]结束,对应着山形状数组的上升部分;
  • ( 2 ) (2) (2)在数组的后缀部分 n u m s [ i . . n − 1 ] nums[i..n−1] nums[i..n1] ,找出一个严格递减的子序列,并且以 n u m s [ i ] nums[i] nums[i]开始,对应着山形状数组的下降部分。

由于我们需要找出最长的山形状数组,并且 n u m s [ 0.. i ] nums[0..i] nums[0..i] n u m s [ i . . n − 1 ] nums[i..n−1] nums[i..n1] 这两部分是互相独立的,那么我们只需要找出 n u m s [ 0.. i ] nums[0..i] nums[0..i] 中以 n u m s [ i ] nums[i] nums[i] 结束的最长严格递增子序列,以及 n u m s [ i . . n − 1 ] nums[i..n−1] nums[i..n1] 中以 n u m s [ i ] nums[i] nums[i] 开始的最长严格递减子序列即可。

求解最长严格递增/递减子序列是一个非常经典的问题,即我们上文提到的 Leetcode 第300题 最长递增子序列 问题,使用动态规划或贪心算法的方法,可以在 O ( n 2 ) O(n^2) O(n2) 或者 O ( n l o g ⁡ n ) O(nlog⁡n) O(nlogn) 的时间内求出给定数组中,以每一个元素结尾的最长严格递增子序列的长度。
最长递增子序列问题的动态规划解法的状态转移方程如下,如果有需要的话,我可以在下一篇更新该问题。
d p [ i ] = max ⁡ 0 ≤ j < i , n u m s [ j ] < n u m s [ i ] d p [ j ] + 1 d p[i]=\max _{0 \leq j<i, n u m s[j]<n u m s[i]} d p[j]+1 dp[i]=0j<i,nums[j]<nums[i]maxdp[j]+1

对于严格递减子序列的部分,我们可以把数组 n u m s nums nums 进行反转,这样就从求解后缀的最长严格递减子序列,变成求解前缀的最长严格递增子序列了。

p r e [ i ] pre[i] pre[i] s u f [ i ] suf[i] suf[i] 分别表示上文 (1)、(2) 中找出的最长子序列的长度,只要 p r e [ i ] pre[i] pre[i] s u f [ i ] suf[i] suf[i]均大于 1,就可以拼接成一个以 n u m s [ i ] nums[i] nums[i] 为最高点的山形状数组,长度为 L = p r e [ i ] + s u f [ i ] − 1 L=pre[i]+suf[i]−1 L=pre[i]+suf[i]1,需要的删除次数为 n − L n−L nL

下面给出的代码使用了 上文提到的 最长递增子序列 问题的代码, 并将其中的代码封装成函数 g e t L I S A r r a y getLISArray getLISArray,用于求解所有的 p r e [ i ] pre[i] pre[i] ,并枚举 i i i 以得出最终的答案。

实现代码(Python)

class Solution:def minimumMountainRemovals(self, nums: List[int]) -> int:pre = self.getLISArray(nums)suf = self.getLISArray(nums[::-1])[::-1]ans = 0for pre_i, suf_i in zip(pre, suf):if pre_i > 1 and suf_i > 1:ans = max(ans, pre_i + suf_i - 1)return len(nums) - ansdef getLISArray(self, nums: List[int]) -> List[int]:n = len(nums)dp = [1] * nfor i in range(n):for j in range(i):if nums[j] < nums[i]:dp[i] = max(dp[i], dp[j] + 1)return dp
复杂度分析:
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2) ,其中 n n n 是数组 n u m s nums nums 的长度。
  • 空间复杂度: O ( n ) O(n) O(n)

题记:


  • 研究生在读,我会尽量保持LeetCode每日一题的思路和代码输出。希望大家多多支持。
  • 水平有限,希望各位大佬能够批评指正。您的教诲是我进步的船帆。
  • 希望各位跟我一样的小白能跟我一起参与到做题和讨论中来。共同进步是我所能期盼的最高愿想。
  • 您的点赞和关注是我坚持分享的动力泉源,希望能将这件简单平凡的事一直做下去。感谢大家。

这篇关于得到山形数组的最少删除次数(LeetCode日记)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

python删除xml中的w:ascii属性的步骤

《python删除xml中的w:ascii属性的步骤》使用xml.etree.ElementTree删除WordXML中w:ascii属性,需注册命名空间并定位rFonts元素,通过del操作删除属... 可以使用python的XML.etree.ElementTree模块通过以下步骤删除XML中的w:as

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

如何在Mac上彻底删除Edge账户? 手动卸载Edge浏览器并清理残留文件技巧

《如何在Mac上彻底删除Edge账户?手动卸载Edge浏览器并清理残留文件技巧》Mac上的Edge账户里存了不少网站密码和个人信息,结果同事一不小心打开了,简直尴尬到爆炸,想要卸载edge浏览器并清... 如果你遇到 Microsoft Edge 浏览器运行迟缓、频繁崩溃或网页加载异常等问题,可以尝试多种方

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA