返回

LeetCode每日一题题解——581.最短无序连续子数组——2021年8月3日|8月更文挑战

前端

背景

581.最短无序连续子数组 Title Description Given an integer array nums, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order. Return the shortest such subarray and output its length.

示例:

输入:nums = [2, 6, 4, 8, 10, 9, 15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行排序。
输入:nums = [1, 2, 3, 4]
输出:0
解释:数组本身就是有序的,所以你不需要改变它。
输入:nums = [1]
输出:0

提示:

  • 1 <= nums.length <= 10^4
  • -10^5 <= nums[i] <= 10^5

题解

算法一:滑动窗口

此算法的思想是使用滑动窗口来查找数组中最长的有序子数组。

步骤:

  1. 初始化一个窗口大小为 1 的窗口,从数组的第一个元素开始。
  2. 扩展窗口,直到窗口内存在无序元素。
  3. 缩小窗口,直到窗口内所有元素有序。
  4. 记录下当前窗口的大小。
  5. 继续移动窗口并重复步骤 2-4,直到窗口到达数组的末尾。
  6. 返回记录下的最小窗口大小。

时间复杂度: O(n),其中 n 是数组的长度。

算法二:两次遍历

此算法首先找到数组中无序部分的最小值和最大值,然后通过两次遍历找到包含这些值的最短连续子数组。

步骤:

  1. 第一次遍历数组,找到最小值和最大值。
  2. 第二次遍历数组,找到第一个大于或等于最小值的元素和最后一个小于或等于最大值的元素。
  3. 返回两个元素之间的索引差加 1。

时间复杂度: O(n),其中 n 是数组的长度。

代码实现

Python:

def findUnsortedSubarray(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    # 算法一:滑动窗口
    l, r = 0, 1
    min_len = len(nums)

    while r < len(nums):
        if nums[r] >= nums[r - 1]:
            r += 1
        else:
            while l < r and nums[r] < nums[l]:
                l += 1
            min_len = min(min_len, r - l)
            r += 1

    # 算法二:两次遍历
    min_val, max_val = float('inf'), float('-inf')
    for num in nums:
        min_val = min(min_val, num)
        max_val = max(max_val, num)

    l, r = 0, len(nums) - 1
    while l < len(nums) and nums[l] <= min_val:
        l += 1
    while r >= 0 and nums[r] >= max_val:
        r -= 1

    return r - l + 1