581 最短无序连续子数组(排序-双指针、栈匹配元素对应的位置)

43 篇文章 0 订阅
37 篇文章 1 订阅

1. 问题描述:

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。你找到的子数组应是最短的,请输出它的长度。

示例 1:

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

  • 输入的数组长度范围在 [1, 10,000]。
  • 输入的数组可能包含重复元素 ,所以升序的意思是<=。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray

2. 思路分析:

① 一开始想到的是双指针的解法,分析题目可以知道不管是从数组左边位置开始或者从右边的位置开始, 当数组元素在其正确的位置的时候那么这个元素左边的所有元素是不需要进行排序的或者是右边的所有元素不需要排序的,所谓正确的位置指的是当前位置元素nums[i]与数组排序后对应位置元素是相等的,例如[2, 6, 4, 8, 10, 9, 15],第一个元素2与最后一个元素15与数组排序之后[2, 4, 6, 8, 9, 10, 15]对应位置是相等的,说明元素2以及左边的所有元素与元素15以及右边的所有元素不需要进行排序的,所以排序范围肯定是他们位置之间的,基于这个想法我们可以先拷贝一份数组元素的副本方便对排序前后的数组元素进行一一比较,因为使用的是python语言,所以可以拷贝一份列表的副本(使用list[:]切片操作进行拷贝)对拷贝的列表副本进行排序,然后我们就可以对原列表与拷贝的副本列表的位置进行一一匹配,判断元素是否相等,因为需要匹配左右边界,所以需要使用指向左右边界的两个指针变量来确定左右边界,其中匹配的时候主要是以下几种情况,其中l,r表示的是列表的左右边界

a : 当列表的左右位置都相等的时候那么同时移动左右指针,也就是将l往右移动, r往左移动,因为排序的范围只能是他们的范围之间

b : 当左边界或者是右边界中只有一个边界对应的数组元素相等的时候那么移动元素相等对应的指针(左边界元素相等那么移动左边界,右边界元素相等那么移动右边界),另外的边界对应的指针不需要移动了,因为这个时候另外一个范围已经确定了(另外一个边界上的元素对应位置肯定是不相等的,因为a中使用if判断两个元素至少存在一个位置的元素不相等了,这个时候存在一个元素相等那么另外一个位置的元素肯定是不相等的)

c : 当列表的左右位置元素都不相等的时候说明这个时候左右范围的元素都是需要重新排序的,这个时候返回左右范围对应的长度即可

整个思路还是挺好理解的

② 看了一下官方提供的题解,发现一个比较不错的思路是使用栈的方法进行解决的,为什么需要使用到栈来解决呢?因为是借助了选择排序的思想,我们知道栈有一个作用是可以用来匹配元素在其适当的位置的,这正好可以使用到这道题目上,我们的目的是需要确定左右边界,所以可以使用栈依次确定最小左边界与最大右边界

a : 确定左边界

我们可以按照列表元素的顺序遍历列表中的元素,按照升序的顺序将数组元素下标存储到列表中,当发现当前遍历的数组元素nums[i] < nums[stack[-1]](-1表示栈顶元素)的时候说明当前这个元素肯定是比栈顶元素之前的位置的,所以我们需要在循环中弹出元素,直到栈为空或者是栈顶元素对应的元素值小于等于了nums[i],这个时候退出循环将当前元素的下标存储到栈中,在弹出元素的同时需要更新左边界,这样就可以找出需要排序的数组元素的最小边界

b : 确定右边界

与上面确定左边界的方法是一样的,只是这里需要倒序遍历列表元素,这样才可以确定需要调整的最大的右边界

最后我们判断一下r - l + 1是否大于0假如大于0我们返回这个值即可,否则返回0

使用栈这个思路确定挺好的,我们可以使用到栈匹配元素在其对应位置的思想应用到其他类似的题目中

3. 代码如下:

排序 + 双指针:

from typing import List


class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        cp = nums[:]
        cp.sort()
        l, r = 0, len(nums) - 1
        res = 0
        while l < r:
            if cp[l] == nums[l] and cp[r] == nums[r]:
                l += 1
                r -= 1
            elif cp[l] == nums[l]:
                l += 1
                res += 1
            elif cp[r] == nums[r]:
                r -= 1
                res += 1
            elif cp[l] != nums[l] and cp[r] != nums[r]:
                return r - l + 1
        return 0

栈匹配元素对应位置:

from typing import List


class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        stack = list()
        l = len(nums)
        for i in range(len(nums)):
            while stack and nums[stack[-1]] > nums[i]:
                poll = stack.pop()
                l = min(l, poll)
            stack.append(i)
        r = 0
        stack.clear()
        # 倒序遍历数组元素找到最右边的边界
        for i in range(len(nums) - 1, -1, -1):
            while stack and nums[stack[-1]] < nums[i]:
                poll = stack.pop()
                r = max(r, poll)
            stack.append(i)
        return 0 if r - l + 1 < 0 else r - l + 1

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值