Java

import java.util.Arrays;

/*
Given an integer array, 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, too.

You need to find the shortest such subarray and output its length.

Example 1:
Input: [2, 6, 4, 8, 10, 9, 15]
Output: 5
Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.
Note:
Then length of the input array is in range [1, 10,000].
The input array may contain duplicates, so ascending order here means <=.

 */

public class Shortest_Unsorted_Continuous_Subarray {

    public static void main(String[] args) {
        Shortest_Unsorted_Continuous_Subarray out = new Shortest_Unsorted_Continuous_Subarray();
        Solution s = out.new Solution();


        int[] input = new int[]{2, 6, 4, 8, 10, 9, 15};
        System.out.println(s.findUnsortedSubarray(input)); // output: 5

        int[] input2 = new int[]{2, 2, 2, 6, 4, 8, 10, 9, 15};
        System.out.println(s.findUnsortedSubarray(input2)); // output: 5

        int[] input3 = new int[]{2, 6, 4, 8, 8, 8, 10, 9, 15};
        System.out.println(s.findUnsortedSubarray(input3)); // output: 7

        int[] sorted = new int[]{1, 2, 3, 4, 5};
        System.out.println(s.findUnsortedSubarray(sorted)); // output: 0
    }

    public class Solution {

        public int findUnsortedSubarray(int[] nums) {

            int[] original = Arrays.copyOf(nums, nums.length);
            Arrays.sort(nums); // o(NlogN)

            int left = 0;
            int right = nums.length - 1;

            while(left < nums.length && nums[left] == original[left]) {
                left++;
            }

            while(right >= 0 && nums[right] == original[right]) {
                right--;
            }

            // @note: key is check final position of left/right
            // one corner case is input is [1,2,3,4]
            return left >= right? 0: right - left + 1;
        }

    }

    public class Solution2 {
        public int findUnsortedSubarray(int[] nums) {

            if (nums == null || nums.length == 0) {
                return 0;
            }

            // logN idea: scan from left to right, compare current with next, if next is smallers, then stop
            //            scan from right to left, compare current with prev, if prev is bigger, then stop
            // failed by: [1,3,2,2,2]

            // idea-2: fix above failure, use a counter for duplicates

            // idea-3: above idea-2 is failed by [1,3,2,3,3], ie, dup count should be applied only when right duplicates are smaller
            // idea-4: above idea-3 is hacky, better to find the localmin and localmax of subarray, then move pointers

            // int dup = 0; // @note: only need to count from right to left scan. left-to-right duplicates are fine
            int left = 0;
            int right = nums.length - 1;

            while(left + 1 < nums.length && nums[left] <= nums[left + 1]) {
                left++;
            }

            while(right - 1 >= 0 && nums[right] >= nums[right - 1]) {
                right--;
            }

            if (left >= right) {
                return 0;
            }

            // try to find local min/max in subarray [left, right]
            int localMin = Integer.MAX_VALUE;
            int localMax = Integer.MIN_VALUE;
            for (int i = left; i <= right; i++) {
                localMin = Math.min(localMin, nums[i]);
                localMax = Math.max(localMax, nums[i]);
            }

            // adjust [left, right] if possible
            while(left >= 0 && nums[left] > localMin) {
                left--;
            }
            while(right <= nums.length - 1 && nums[right] < localMax) {
                right++;
            }

            return right - left - 1; // @note: here -1, since above 2 while will move left/right at least once for each

            // // decide if to apply duplicate count
            // dup = (right + 1 >= nums.length || nums[left] <= nums[right + 1])? 0: dup;
            // return right - left + 1 + dup;
        }
    }

}

Java

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int length = nums.length;
        int[] sorted = new int[length];
        System.arraycopy(nums, 0, sorted, 0, length);
        Arrays.sort(sorted);
        int low = -1;
        for (int i = 0; i < length; i++) {
            if (nums[i] != sorted[i]) {
                low = i;
                break;
            }
        }
        if (low < 0)
            return 0;
        int high = length;
        for (int i = length - 1; i >= 0; i--) {
            if (nums[i] != sorted[i]) {
                high = i;
                break;
            }
        }
        return high - low + 1;
    }
}

All Problems

All Solutions