时间复杂度:O(n)
解题思路
令[left,right]表示无序区间,那么[0,left)和(right,n]一定有序,且前者所有元素均小于无序区间元素,后者所有元素均大于无序区间元素。
那么我们要想求right,就一定要找到第一个大于无序区间最大元素且右侧均有序的元素,该元素位置的左侧就是我们要求的right。
同理要想求left,就一定要找到第一个小于无序区间最小元素且左侧均有序的元素,该元素位置右侧就是我们要求的left。
从思路上看我们需要两遍遍历,但是其实我们一遍遍历就能完成,可以看做是一个头指针和一个尾指针同时向中间移动,头指针负责求right,尾指针负责求left。
对于有序的数组我们需要特判,那就是right为初始值没有发生改变,否则返回right-left+1就是无序区间长度。
AC代码
func findUnsortedSubarray(nums []int) int {
left,right:=-1,-1
rightMax,leftMin:=math.MinInt64,math.MaxInt64
n:=len(nums)
for i,num:=range nums{
if rightMax>num{
right=i
}else{
rightMax=num
}
if leftMin<nums[n-1-i]{
left=n-1-i
}else{
leftMin=nums[n-1-i]
}
}
if right==-1{
return 0
}
return right-left+1
}
感悟
自己其实写了一个AC代码,思路和官方题解思路基本一致,不过我想的稍稍有些复杂了,并且没有想到两遍遍历可以用n-i-1实现一遍遍历。
自己写的AC代码如下,就当看个笑话了。
func findUnsortedSubarray(nums []int) int {
left,right:=1,0
meetBig,meetSmall:=true,true
for i:=1;i<len(nums);i++{
if meetBig&&nums[i]<nums[i-1]{
right=i
meetBig=false
}else if !meetBig&&nums[i]>=nums[right-1]{
right=i-1
meetBig=true
}
}
if !meetBig{
right=len(nums)-1
}
for i:=len(nums)-2;i>=0;i--{
if meetSmall&&nums[i]>nums[i+1]{
left=i
meetSmall=false
}else if !meetSmall&&nums[i]<=nums[left+1]{
left=i+1
meetSmall=true
}
}
if !meetSmall{
left=0
}
return right-left+1
}