首页 > 编程语言 >算法随笔_12:最短无序子数组

算法随笔_12:最短无序子数组

时间:2025-01-19 23:27:37浏览次数:3  
标签:12 nums max 最短 排序 数组 升序 随笔 left

上一篇: 算法随笔_11: 字符串的排列-CSDN博客

题目描述如下:

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。请你找出符合题意的最短子数组,并输出它的长度。

示例 1:

输入:nums = [2,6,4,8,10,9,15]

输出:5

解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

===================

我们一起来分析一下这道题。

需要找出的这个子数组可以是任意的位置。不失一般性的,我们可以假设这个子数组的起始点在原来数组的中间某处。我们假设这个子数组为nums_mid,那么此时它分割出来左右两个子数组分别为nums_left,nums_right。按照题意,如果对子数组nums_mid进行升序排序,整个数组都会变为升序排序,那么原数组应该有以下的特征:

仅对子数组nums_mid进行升序排序,就相当于对全数组进行了排序。反过来说,对全数组进行排序,其实只是把nums_mid进行了排序。在排序的前后,nums_left,nums_right两个子数组的序列是不变的。

基于此特征,我们可以写出如下算法:

我们对原数组进行升序排序。排序之后,我们把排序之后的数组与原数组从左到右逐个字符的进行比较。当发现第一个出现不同的字符时,我们就找到了nums_left。同理,从右至左逐个字符的进行比较,我们就找到nums_right。那么,中间的这一块儿就是nums_mid。其长度即可算出。

此算法的时间复杂度为O(nlogn) 。

==================

让我们再考虑一下有没有更优的算法?

让我们重新审视一下原题的描述。nums_mid不论是否排序,它里面的任何一个元素都比nums_left中的任何一个元素大。nums_right在排序前后本身就不改变序列,因此,它的任何一个元素也比nums_left的任何一个元素大。因此,nums_left有如下特征:

1. 它是一个升序排列。

2. 它的最大值一定比后面所有数的最小值还要小。

基于此特征,我们可以给出如下的算法:

1. 我们设置两个变量,nums_left_max(表示nums_left的最大值的下标),和left_min(表示nums_left后面所有数的最小值)。

2. 我们从右向左遍历原数组,记录当前已经遍历过的元素的最小值left_min。并且每个当前访问的元素e和left_min比较,会有下面两种情况:

   a. 如果e小于left_min,并且nums_left_max为-1,我们记录当前下标为nums_left_max。

   b. 如果e大于left_min,那么nums_left_max肯定不为当前的下标。我们把nums_left_max重置为1。

遍历完成后我们就找到了nums_left_max。

同理,我们可以求出nums_right_min(表示nums_right的最小值的下标)。

最终两数相减即为题目答案。由于此算法只执行了一次遍历,因此时间复杂度为O(N) 。

算法具体实现时注意一下边界条件。实际代码如下:

class Solution(object):
    def findUnsortedSubarray(self, nums):
        n=len(nums)
        nums_left_max=-1
        nums_right_min=n
        left_min=float('inf')
        right_max=float('-inf')
        for i in range(n):
          if right_max<=nums[i]:
            right_max=nums[i]
            if nums_right_min==n:
              nums_right_min=i
          else:
            nums_right_min=n
              
          if left_min>=nums[n-i-1]:
            left_min=nums[n-i-1]
            if nums_left_max==-1:
               nums_left_max=n-i-1
          else:
             nums_left_max=-1
        ret=nums_right_min-nums_left_max-1
        ret=0 if ret<0 else ret
        return ret

标签:12,nums,max,最短,排序,数组,升序,随笔,left
From: https://blog.csdn.net/m0_70494097/article/details/145240099

相关文章

  • oracle使用case when报错ORA-12704字符集不匹配原因分析及解决方法
    问题概述使用oracle的casewhen函数时,报错提示ORA-12704字符集不匹配,如下图,接下来分析报错原因并提出解决方法。样例演示现在有一个TESTTABLE表,本表包含的字段如下图所示,COL01字段是NVARCHAR2类型,COL02字段是VARCHAR2类型。场景一使用case简单函数,case后面的内容和when......
  • 123. 买卖股票的最佳时机
    123.买卖股票的最佳时机III/***@param{number[]}prices*@return{number}*/varmaxProfit=function(prices){if(prices.length===1)return0;letinit=null/**dp[i][0]:无操作;dp[i][1]:第一次买入;dp[i][2]:第一......
  • 121. 买卖股票的最佳时机
    买卖股票的最佳时机/***@param{number[]}prices*@return{number}*/varmaxProfit=function(prices){letmax=0;for(leti=0;i<prices.length;i++){for(letj=i+1;j<prices.length;j++){letprofit=prices[j]-prices[......
  • LeetCode:122.买卖股票的最佳时机II
    LeetCode:122.买卖股票的最佳时机IImathtcg4d..解题思路前提:上帝视角,知道未来的价格。局部最优:见好就收,见差就不动,不做任何长远打算。解题步骤新建一个变量,用来统计总利润。遍历价格数组,如果当前价格比昨天高,就在昨天买,今天卖,否则就不交易。遍历结束后,返回所有利润之和。/**......
  • 12000台虚拟机大迁移!又一家公司宣布弃用VMware,自制KVM平台替代
    曾几何时,提起虚拟化,VMware是一家绕不开躲不过的公司,它也是第一个虚拟化x86架构并取得商业成功的公司,备受业界关注。可惜的是,自从2023年11月,VMware被博通以610亿美元收购,后者对其进行大刀阔斧地改革,并把VMware原有云服务的“永久许可证”改为了订阅制度之后,遭到了不......
  • 算法随笔_9:压缩字符串
    上一篇: 算法随笔_8:寻找重复数-CSDN博客题目描述如下:给你一个字符数组 chars ,请使用下述算法压缩:从一个空字符串 s 开始。对于 chars 中的每组连续重复字符 :如果这一组长度为 1 ,则将字符追加到 s 中。否则,需要向 s 追加字符,后跟这一组的长度。压缩后得到......
  • 5MW风电永磁直驱发电机-1200V直流并网Simulink仿真模型
      ......
  • 12 分布式事务
    分布式事务产生的原因我们拿mysql数据库来说,当数据库为单体数据库的时候,我们打开事务,执行sql为预执行阶段,最后commit时通过日志控制最终全部提交后存储到磁盘中,如果commit失败,可以通过日志控制回滚回来,但是当我们的数据库实例为多个的时候,不同的数据源,我们的日志已经无法控......
  • 2025dsfz集训Day5:最短路与最小生成树
    DAY5I:最小生成树生成树及最小生成树生成树是从一张无向连通图中选取一些边构成一张新图,使得这张图是是一棵树最小生成树即是让上述的生成树的边权和最小同时,最小生成树也会有一些性质在最小生成树上,两个点路径上经过的边权最小值即是这个点在原图中所有路径中可能经过......
  • 202312 青少年软件编程等级考试C/C++ 二级真题答案及解析(电子学会)
    第1题统计指定范围里的数给定一个数的序列S,以及一个区间[L,R],求序列中介于该区间的数的个数,即序列中大于等于L且小于等于R的数的个数。时间限制:1000内存限制:65536输入第一行1个整数n,表示序列的长度。(0<n≤10000) 第二行n个正整数,表示序列里的每一个数,每个数小于等......