LeetCode problem: 581. Shortest Unsorted Continuous Subarray.
Given an array, find the length of the smallest subarray in it which when sorted will sort the whole array.
Example 1:
Input: [1, 2, 5, 3, 7, 10, 9, 12]
Output: 5
Explanation: We need to sort only the subarray [5, 3, 7, 10, 9] to make the whole array sorted
Example 2:
Input: [1, 3, 2, 0, -1, 7, 10]
Output: 5
Explanation: We need to sort only the subarray [1, 3, 2, 0, -1] to make the whole array sorted
Example 3:
Input: [1, 2, 3]
Output: 0
Explanation: The array is already sorted
Example 4:
Input: [3, 2, 1]
Output: 3
Explanation: The whole array needs to be sorted.
The algorithm first creates a sorted copy of the input array. It then iterates through both the input and sorted arrays to identify the start and end indices of the unsorted subarray.
By comparing corresponding elements in the input array and the sorted array, it finds the first and last positions where the elements differ.
Complexity analysis:
- Time complexity: O(N * LogN)
- Space complexity: O(N)
def findUnsortedSubarray(nums: List[int]) -> int:
sorted_nums = list(sorted(nums))
start = None
end = None
for i in range(len(nums)):
if nums[i] != sorted_nums[i]:
if start is None:
start = i
end = i
else:
end = i
return (end - start) + 1 if start is not None else 0
The algorithm starts by identifying both the start and the end of the candidate unsorted subarray through the following steps:
- It begins from the start of the array to find the first element that is out of order (i.e., an element smaller than its previous element).
- Similarly, it starts from the end of the array to find the first element that is out of order (i.e., an element larger than its previous element).
But sorting this subarray may not necessarily result in the entire array being sorted. Here is an example:
Input: [1, 3, 2, 0, -1, 7, 10]
Sorting the numbers between '3' and '-1' will not sort the whole array: [1, -1, 0, 2, 3, 7, 10]
This happens when any of the following two conditions is met:
- There is a number before the candidate unsorted subarray that is larger than any number in the unsorted subarray.
- There is a number after the candidate unsorted subarray that is smaller than any number in the unsorted subarray.
To sort the entire array, it is necessary to include all such elements that are larger than the smallest element of the unsorted subarray and all elements that are smaller than the largest element of the unsorted subarray.
Therefore, the final algorithm proceeds as follows:
- From the beginning of the array, find the first element that is out of order. This element marks the start of the candidate unsorted subarray.
- From the end of the array, find the first element that is out of order. This element marks the end of the candidate unsorted subarray.
- Find the minimum and maximum values within this unsorted subarray.
- Extend the subarray to the left to include any elements that are larger than the minimum value of the unsorted subarray.
- Similarly, extend the subarray to the right to include any elements that are smaller than the maximum value of the unsorted subarray.
Complexity analysis:
- Time complexity: O(N)
- Space complexity: O(1)
# O(N) time and O(1) space
def findUnsortedSubarrayIndices(nums: List[int]) -> Tuple[Optional[int], Optional[int]]:
left = 0
while left < len(nums) - 1 and nums[left] <= nums[left + 1]:
left += 1
# if the array is sorted
if left == len(nums) - 1:
return None, None
right = len(nums) - 1
while right > 0 and nums[right] >= nums[right - 1]:
right -= 1
return left, right
# O(N) time and O(1) space
def findSubarrayMinimumAndMaximum(nums: List[int], start: int, end: int) -> Tuple[int, int]:
minimum = float("inf")
maximum = float("-inf")
for i in range(start, end + 1):
minimum = min(minimum, nums[i])
maximum = max(maximum, nums[i])
return minimum, maximum
def findUnsortedSubarray(nums: List[int]) -> int:
start, end = findUnsortedSubarrayIndices(nums)
# if the array is sorted
if start is None and end is None:
return 0
# find minimum and maximum numbers in the unsorted subarray
minimum, maximum = findSubarrayMinimumAndMaximum(nums, start, end)
# expand the subarray to the left to include any element before the subarray
# which is smaller than the minimum element of the unsorted subarray
temp = start - 1
while temp >= 0:
if nums[temp] > minimum:
start = temp
temp -= 1
# expand the subarray to the right to include any element after the subarray
# which is larger than the maximum element of the unsorted subarray
temp = end + 1
while temp <= len(nums) - 1:
if nums[temp] < maximum:
end = temp
temp += 1
return (end - start) + 1