leetcode581 最短无序连续子数组

题目

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。

示例

输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

解析

这道题目的意思就是,将一个数组分为3部分,最前面的部分是升序的,最后面的部分是降序的,中间可能乱序,把中间的排一下,使得整体有序就可以了
先用一种开辟新数组后排序比较的方法:

func findUnsortedSubarray(nums []int) int {
	if sort.IntsAreSorted(nums) { // 判断数组是否已经升序
		return 0
	}
	var numsSorted []int
	numsSorted = append(numsSorted, nums...)
	sort.Ints(numsSorted)
	left := 0
	right := len(nums) - 1
	for nums[left] == numsSorted[left] {
		left++
	}
	for nums[right] == numsSorted[right] {
		right--
	}
	return right - left + 1
}

上面这个方法当然不是最好的解法,但各种题解说的云里雾里的,看了好长时间,还是再整理下好的解法。首先是要这个数组最终有序的,那么起一个for循环来遍历,同时从左往右和从右往左。从左往右的话,应该是递增对吧,那么先设定的叫tmpMax的最大值,符合递增就不断更新最大值,直到不满足递增了,说明这个数字不对,需要重新排序,先记录下下标,然后继续遍历,有符合条件的就更新。
用题目中给的例子解释下:2 6 4 8 10 9 15
从左往右更新max的时候,会先被更新成6,遇到4的时候发现逆序了,把4更新成右边界,继续遇到8了更新成max,遇到10了更新成max,遇到9了,逆序,记录9为右边界,之后max更新成15。
从右往左更新min的时候,先是15,然后9,遇到10了逆序记录左边界,然后min更新成8,然后4,遇到6了逆序更新左边界,最后更新成2。
所以无序的区间就是从6到9的部分。
这个思路用到的想法就是,前后有两段有序的部分,在有序的部分,你从左往右更新max肯定是在一直更新的,从右往左更新min也是同理,但遇到了无序的部分就不一定,下个元素可能会小于max,也可能会大于min。因为无序一定有这一性质,那么记录这一条件最后得到的肯定是无序的左右边界。

func findUnsortedSubarray(nums []int) int {
	n := len(nums)
	if n < 2 {
		return 0
	}
	leftMax := nums[0]    // 左边的最大值
	rightMin := nums[n-1] // 右边的最小值
	left := 0
	right := -1 // 因为最后结果要+1,比如默认有序的情况,所以这初始化为-1
	for i := 0; i < n; i++ {
		if leftMax > nums[i] {
			right = i
		} else {
			leftMax = nums[i]
		}

		if rightMin < nums[n-i-1] {
			left = n - i - 1
		} else {
			rightMin = nums[n-i-1]
		}
	}
	return right - left + 1
}

你可能感兴趣的:(#,leetcode贪心系列,算法,数据结构,排序算法)