581.最短无序连续子数组
题目描述:
给你一个整数数组nums,你需要找出一个连续子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的最短子数组,并输出它的长度。
示例1:
输入:nums = [2, 6, 4, 8, 10, 9, 15]
输出:5
解释:你只需对[6, 4, 8, 10, 9]进行升序排序,那么整个表都会变为升序排序。
示例2:
输入:nums = [1, 2, 3, 4]
输出:0
示例3:
输入:nums = [1]
输出:0
提示:
- 1 <= nums.length <= 10^4
- -10^5 <= nums[i] <= 10^5
思路:排序、双指针遍历
1、排序:
依据题意,可以将给定的数组分为三段,分别记为nums1、nums2、nums3。对nums2进行排序后,整个nums数组将变为升序数组。
要求找到最短的nums2,即找到最长的nums1和nums3的长度和。所以相当于找到最长的前缀子数组nums1和最长的后缀子数组nums2。
具体操作方面,当原数组有序或长度<=1时,可以直接返回0。其他情况下可以拷贝nums数组,并对拷贝后的数组进行排序,然后从左到右找到第一个两个数组不同的位置,作为nums2的左边界;同理找到nums2的右边界,最后输出nums2的长度。
python代码:
class Solution:
def findUnsortedSubarray(self, nums: List[int]) -> int:
# 方法一排序
# 判断长度是否<=1和是否本身就为升序
n = len(nums)
if n == 1:
return 0
else:
def isSorted():
for i in range(1, n):
if nums[i-1] > nums[i]:
return False
return True
if isSorted():
return 0
# 拷贝数组
newnums = sorted(nums)
# 找到nums2左右起始点
left = 0
right = n-1
while nums[left] == newnums[left]:
left += 1
while nums[right] == newnums[right]:
right -= 1
return right - left + 1
2、双指针遍历
如前一个思路所述要找到nums2,假定nums2在nums中对应的区间为[left, right]。
对于nums1的每一个元素而言,nums2和nums3中的每个元素都比它们大。对于nums3而言同理,每个元素都比nums1和nums2中的元素大。
因此可以使用枚举法,找到nums中位置为left的元素使得它右边的元素比他小,位置为right的元素使得它左边的元素比他大。
python代码:
class Solution:
def findUnsortedSubarray(self, nums: List[int]) -> int:
# 方法二双指针直接遍历
# 初始化一些值
n = len(nums)
maxn, right = float('-inf'), -1
minn, left = float('inf'), 1
# 循环遍历找到left和right
for i in range(n):
if maxn > nums[i]:
right = i
else:
maxn = nums[i]
if minn < nums[n-i-1]:
left = n-i-1
else:
minn = nums[n-i-1]
# 返回结果
return 0 if right == -1 else right - left + 1