Given an integer array nums,
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.
Return the shortest such subarray and output its length.
Example 1:
Input: nums = [2,6,4,8,10,9,15]
Output: 5
Example 2:
Input: nums = [1,2,3,4]
Output: 0
Example 3:
Input: nums = [1]
Output: 0
class Solution {
var nums: [Int] = []
let INF = 987654321
func upperBound(_ s: Int, _ e: Int, _ target: Int) -> Int {
var s = s, e = e
while s < e {
let mid = (s + e) / 2
if nums[mid] <= target { s = mid + 1}
else { e = mid }
}
return e
}
func lowerBound(_ s: Int, _ e: Int, _ target: Int) -> Int {
var s = s, e = e
while s < e {
let mid = (s + e) / 2
if nums[mid] < target { s = mid + 1}
else { e = mid }
}
return e
}
func findStartNode() -> Int {
for i in 1..<nums.count {
if nums[i] < nums[i - 1] {
return i - 1
}
}
return -1
}
func findEndNode() -> Int {
for i in (0..<(nums.count - 1)).reversed() {
if nums[i] > nums[i + 1] {
return i + 1
}
}
return -1
}
func findUnsortedSubarray(_ nums: [Int]) -> Int {
self.nums = nums
let startNode = findStartNode()
if startNode == -1 { return 0 }
let endNode = findEndNode()
if endNode == -1 { return nums.count }
var maxVal = -INF, minVal = INF
for i in startNode...endNode {
maxVal = max(maxVal, nums[i])
minVal = min(minVal, nums[i])
}
let s = upperBound(0, startNode, minVal)
let e = lowerBound(endNode, nums.count, maxVal)
return e - s
}
}