AlgoMaster Logo

Shortest Unsorted Continuous Subarray

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We have an array that might be almost sorted, meaning most of it is in order but some middle section is out of place. The task is to find the smallest window that, if we sorted only that part, the entire array would become sorted.

The complication is that the unsorted section is not always the obvious one. A single misplaced element can extend the unsorted window further than its own position. Consider [1, 3, 2, 2, 2]: the 3 at index 1 is the only value that looks wrong, but the window has to stretch all the way to index 4, because every 2 after the 3 is smaller than it and would move during a sort.

The unsorted subarray is bounded by two positions. On the left, the first position holding an element greater than something that comes after it. On the right, the last position holding an element smaller than something that came before it. The work is finding these two boundaries efficiently.

Key Constraints:

  • 1 <= nums.length <= 10^4 → With n up to 10,000, an O(n^2) approach (around 10^8 comparisons) is borderline, while O(n log n) and O(n) are comfortable.
  • -10^5 <= nums[i] <= 10^5 → Values fit in a 32-bit int with no overflow concern, and duplicates are allowed because the target order is non-decreasing, not strictly increasing. The comparisons below use strict < and > so equal neighbors are never flagged as out of place.

Approach 1: Sorting and Comparing

Intuition

If we know what the fully sorted array looks like, we can compare it to the original element by element. The first position where the two differ is the left boundary of the unsorted subarray, and the last position where they differ is the right boundary.

This works because every element outside the unsorted window already sits in its correct sorted position, so it matches the sorted copy. The elements inside the window are exactly the ones that would move during a full sort, so they are the ones that differ.

Algorithm

  1. Create a sorted copy of the array.
  2. Compare the original array with the sorted copy from left to right. Find the first index where they differ. This is the left boundary.
  3. Compare from right to left. Find the last index where they differ. This is the right boundary.
  4. If no differences are found, the array is already sorted, so return 0.
  5. Return right - left + 1.

Visualization and Code

Loading animation...

The full sorted order is more than we need. The next approach finds the same two boundaries directly, in linear time and constant extra space, by detecting where elements sit lower or higher than their neighbors require.

Approach 2: Two-Pass with Running Max/Min (Optimal)

Intuition

In a fully sorted array, each element is at least as large as everything before it and at most as large as everything after it. We can find the unsorted boundaries by checking where this fails.

Scanning left to right, track the maximum seen so far. Any element smaller than that running maximum is out of place: a larger value already appeared earlier, so this element would have to move left during a sort. The rightmost such element is the right edge of the unsorted window. Everything past it is larger than the entire prefix, so it never moves.

Scanning right to left, track the minimum seen so far. Any element larger than that running minimum is out of place, because a smaller value appears later and this element would move right. The leftmost such element is the left edge of the window.

This captures the window's full extent even when the source of the disorder sits at one end. In [1, 3, 2, 2, 2], the running maximum becomes 3 at index 1, and every later 2 is smaller than 3, so each one is flagged and the right edge extends to index 4.

Algorithm

  1. Initialize right = -1 (will store the right boundary of unsorted subarray).
  2. Scan left to right, tracking the running maximum. Whenever an element is less than the running max, update right to the current index.
  3. Initialize left = 0 (will store the left boundary).
  4. Scan right to left, tracking the running minimum. Whenever an element is greater than the running min, update left to the current index.
  5. If right == -1, the array is already sorted, return 0.
  6. Return right - left + 1.

Visualization and Code

Loading animation...