二维数组排序 行与列分别升序_leetcode581. 最短无序连续子数组

leetcode581. 最短无序连续子数组

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

你找到的子数组应是最短的,请输出它的长度。

示例 1:

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

说明 :

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

方法一:排序+双指针

思路:

这道题的首先想到的方法比较暴力,既然要找到最短需要排序的数组,那么我们就将数组排序,然后使用左右两个指针,找到左边第一个与原来元素不一样的位置和右边第一个与原来元素不一样的位置,这两个指针中间的数组就是答案,返回长度即可。

需要注意的是,如果左右指针遍历过后,j<=i,那么说明原数组就是有序的,返回0;j=i是特殊情况,此时数组只有一个元素,显然是有序的。

复杂度分析:

  • 使用python的sort函数,需要nlogn,之后双指针最差情况是2n,所以综合起来时间复杂度为O(NlogN)
  • 使用了一个额外的数组来存放原来的数组,因此空间复杂度为O(N)

代码:

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        #存放原数组
        temp = []
        temp[:] = nums[:]
        #排序
        nums.sort()
        n = len(nums)
        #左指针,找到第一个不匹配的下标
        i = 0
        while i < n:
            if nums[i] == temp[i]:
                i += 1
            else:
                break
        j = n-1
        #右指针,找到右边第一个不匹配的下标
        while j >= 0:
            if nums[j] == temp[j]:
                j -= 1
            else:
                break
        #返回答案,如果j<=i,说明原来的数组就是有序数组
        return j-i+1 if j-i>0 else 0

结果:

56b3f9e6b509b9ba66883e9a7601a3a0.png

方法二:单调栈

思路:

这种方法与上面类似,都是找到最后左边第一个不匹配以及右边第一个不匹配,只不过我们不是使用排序之后对比,我们使用单调栈来找到这两个位置,也就是无序数组的左右下标。

首先找到左下标,从左边遍历数组,将它的下标入栈。遍历的时候,比较这个元素与栈顶下标对应的元素大小,如果大于等于它,证明目前还是升序的,不是无序的,就入栈......如果小于栈顶坐标对应的元素,那么证明这个元素的位置肯定不对,我们需要找到它的位置,将栈顶出栈,目前遍历的元素起码需要与它换位,继续与栈顶对应的元素比较......直到栈顶对应的元素小于目前遍历的元素,那么这个元素需要变换到的位置就是上一个出栈元素的位置,使用left保存。再将这个元素入栈。不断遍历重复这个过程,left保留最小的需要变换位置...那么最后的left就是无序数组的左下标(即需要换位的最小元素需要换到的位置)

同理,我们再从右遍历数组,维护一个递减栈,找到需要换位的最大元素需要换到的位置,也就是无序数组的右下标right。

最后与上种方法一样,如果right>left,返回right-left+1,否则返回0。

复杂度分析:

  • 因为没有进行排序,只是遍历了两次数组,因此时间复杂度为O(2N)→O(N)
  • 使用了一个栈,最长为N,空间复杂度为O(N)

代码:

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        stack = []
        n = len(nums)
        left = n-1
        right = 0
        #从左边遍历,找到无序数组的左下标
        for i in range(n):
            while stack and nums[i] < nums[stack[-1]]:
                temp = stack.pop()
                left = min(left,temp)
            stack.append(i)
        stack = []
        #从右边遍历,找到无序数组的右下标
        for i in range(n-1,-1,-1):
            while stack and nums[i] > nums[stack[-1]]:
                temp = stack.pop()
                right = max(right,temp)
            stack.append(i)
        return right-left+1 if right>left else 0

结果:

a49da52fce79dfc2aa5aca2ad60cc5f6.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值