📅  最后修改于: 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)$。