📜  最短无序子数组(1)

📅  最后修改于: 2023-12-03 15:10:37.225000             🧑  作者: Mango

最短无序子数组

随着数据处理的不断高效,人们对于数据的处理需求越来越多样化,其中数组排序是很常见的需求。从一个数组中我们可以十分容易地得到排序后的结果,但有时我们需要找出最短的无序子数组,即对这个子数组排序后即可使整个数组有序。本文将对这个问题进行介绍并给出一种解决方案。

问题描述

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

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

解决方案
方法一:暴力枚举

暴力枚举是最能想到的一种方法。我们可以对每一个子数组进行排序,然后判断其是否已经有序。最后找到长度最短的无序子数组即可。

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2:
            return 0
        
        res = n
        for i in range(n):
            for j in range(i, n):
                if self.isSorted(nums, i, j):
                    res = min(res, j - i + 1)
        return res
    
    def isSorted(self, nums, i, j):
        for k in range(i, j):
            if nums[k] > nums[k+1]:
                return False
        return True

由于该算法需要对每一个子数组进行排序,时间复杂度为 $O(n^3 \log n)$,无法通过本题。

方法二:排序

朴素的想法是将原数组进行排序,然后比较原数组和排序后的数组,找到两者第一次发生不同的位置,即为最短无序子数组的位置。

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2:
            return 0
        
        sorted_nums = sorted(nums)
        i = 0
        while i < n and nums[i] == sorted_nums[i]:
            i += 1
        
        j = n - 1
        while j > i and nums[j] == sorted_nums[j]:
            j -= 1
        
        return j - i + 1 if j != i else 0

该算法时间复杂度为 $O(n \log n)$,但它破坏了原数组的顺序,不符合题目要求。

方法三:栈

我们可以使用栈找到最左边和最右边的无序数字。详细实现可以参考下面的代码。

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2:
            return 0
        
        stack = []
        left, right = n - 1, 0
        for i in range(n):
            while stack and nums[stack[-1]] > nums[i]:
                left = min(left, stack.pop())
            stack.append(i)
        
        stack.clear()
        for i in range(n-1, -1, -1):
            while stack and nums[stack[-1]] < nums[i]:
                right = max(right, stack.pop())
            stack.append(i)
        
        return right - left + 1 if right > left else 0

该算法的时间复杂度仅为 $O(n)$,空间复杂度为 $O(n)$。