问题描述
Given an integer array, 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, too.
You need to find the shortest such subarray and output its length.
Note:
- Then length of the input array is in range [1, 10,000].
- The input array may contain duplicates, so ascending order here means <=.
给定一个整数数组,你需要找到一个连续的子数组,如果只按升序对这个子数组排序,那么整个数组也将按升序排序。
你需要找到最短的子数组并输出它的长度。
注意:
那么输入数组的长度在[1,10,000]范围内。
输入数组可能包含重复项,所以这里升序表示<=。
输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
Python 实现
实现一:排序后再通过比较找出边界。简单粗暴的方法,直接上代码。
class Solution(object):
def findUnsortedSubarray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
if length <= 1:
return 0
arr = sorted(nums)
length = len(nums)
for i in range(length):
if arr[i] != nums[i]:
break
for j in range(length, 0, -1):
if arr[j-1] != nums[j-1]:
break
if j-1 < i:
return 0
else:
return j-i
实现二:寻找左右两个边界。思路和冒泡排序法有点类似,但我们并不是真的进行排序。我们知道,冒泡排序法就是遍历时将前后两个元素进行对比,(假设是升序排序)较大值会被交换到靠后的位置。在这一道题目里,我们不把较大值交换到靠后的位置,而是记录这个最大值,并以之为比较标准,位置靠后且小于该最大值的元素,必然是整个数组排序时需要考虑的部分,也就是我们所要求的最短无排序连续子数组的元素之一,因此我们记录下最靠后的最小值的索引,即为所求子数组的右边界。同理,从右往左遍历,相当于通过冒泡排序法排成降序的形式,我们记录中间出现的最小值作为比较对象,记录最后出现的较大值的索引,即为左边界。
使用上述方法,最多需要遍历两次数组(前后各一次),需要4个变量来记录最大值、最小值、左边界、右边界,因此时间复杂度为 O(n),空间复杂度为 O(1)。
class Solution(object):
def findUnsortedSubarray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
if length <= 1:
return 0
left = right = -1
maxEdge = nums[0]
minEdge = nums[length-1]
for i in range(1, length):
maxEdge = max(maxEdge, nums[i])
if maxEdge > nums[i]:
right = i
if right == -1:
return 0
for j in range(length-1, 0, -1):
minEdge = min(nums[j-1], minEdge)
if minEdge < nums[j-1]:
left = j-1
return right - left + 1
链接:https://leetcode.com/problems/shortest-unsorted-continuous-subarray/