1

I have been wrestling with this problem for quite a bit:

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.

(cmp. https://leetcode.com/problems/shortest-unsorted-continuous-subarray/).

I'm still stuck on the main approach of this problem. It's splitting my head in two.

Suppose we have this given array:

[1,2,5,3,7,10,9,12]

The answer is "5", pertaining the subarray between '5' and '9'.

My approach for this problem is basically like this:

  1. Create a "maxes" array where every index represents the max value found up to that index.

  2. Create a "mins" array where every index represents the min value found up to that index.

  3. The respective discrepancies between 'maxes' and the input array, and the discrepancies between 'mins' and the input array, will give us the 'start' and 'end' index. Subtract the two to find the length of the subarray. (This step isn't important for my question, I'm stuck before this part.)

**

Thus for the "maxes" array, it would look like:

input: [1,2,5,3,7,10,9,12] ->

maxes: [1,2,5,5,7,10,10,12]

Where index 0 is "1" because '1' is the "max" value found up to that index. Index 1 is "2" because '2' is the "max' value found up to that index. And so forth.

We then find the highest index that's a mismatch between the input array and maxes array.

My question is when I try this approach for the 'mins' array:

input: [1,2,5,3,7,10,9,12] ->

mins: [1,1,1,1,1,1,1,1]

If I start from the left, it all just becomes 1.

Should I start at the end (right) instead? And if I do, why do I have to start it at the end?

buddemat
  • 4,552
  • 14
  • 29
  • 49
  • Thinking this way - just sort the list and compare/check if the num. is the right number (at the spot) – Daniel Hao Jul 14 '21 at 12:35
  • Interesting approach. But I think it will work. Yes you start at the end to get the mins because you sort in ascending order. Then you can go from left to right and the first index where max is not equal to min is the start i.e. go from right to left and the first inequality is the end. – maraca Jul 14 '21 at 20:33

1 Answers1

1

Your approach seems generally fine. You are correct that you need to work backwards to construct the mins array. The reason is that in the same way the current maximum is "propagated" forward in the maxes array, the current minimum is "propagated" backwards from the end in the mins array.

Consider the input array [2,3,5,1,12,7,10,9,11] which is built in a way such that the Shortest Unsorted Continuous Subarray is the whole array itself.

If you use your approach, you can see that the maximum "pushes" the value 12 from the middle to the end and the minimum does the same for the 1 from the middle to the start.

Index    0  1  2  3  4  5  6  7  8

Input  [ 2, 3, 5, 1,12, 7,10, 9,11]
 
Maxes  [ 2, 3, 5, 5,12,12,12,12,12]
                                 ^
                             maxes_idx

Mins   [ 1, 1, 1, 1, 7, 7, 9, 9,11] 
         ^   
      mins_idx    

For your data, this gets you the correct indices:

Index    0  1  2  3  4  5  6  7

Input  [ 1, 2, 5, 3, 7,10, 9,12]
 
Maxes  [ 1, 2, 5, 5, 7,10,10,12]
                           ^
                         maxes_idx

Mins   [ 1, 2, 3, 3, 7, 9, 9,12] 
               ^   
            mins_idx    

Then compute the length as length = maxes_idx - mins_idx + 1, which in the case above would be length = 6 - 2 + 1 = 5.


Instead of doing this with the two sequences maxes and mins, you could also compare input with a sorted version of itself and find both indices from that:

  1. sort input to get sorted.
  2. find lower_idx as the first index, where input and sorted do not match.
  3. find upper_idx as the last index, where input and sorted do not match.
  4. compute length = upper_idx - lower_idx + 1
Index    0  1  2  3  4  5  6  7

Input  [ 1, 2, 5, 3, 7,10, 9,12]
 
Sorted [ 1, 2, 3, 5, 7, 9,10,12]
               ^           ^ 
         lower_idx       upper_idx

The latter approach is a bit easier to grasp, but worse in terms of complexity (fastest sort alone has a time complexity of O(n log n)) and also more effort to code in case you have to implement the sorting yourself.


Another approach (time complexity O(n)) does not require constructing one or more versions of the array for comparison at all:

  1. find the first index i from the start which violates the condition of a sorted array (i.e. input[i] > input[i+1]).

    Find the last index j from the end which violates the condition of a sorted array (i.e. input[j-1] > input[j])

    Index    0  1  2  3  4  5  6  7
    
    Input  [ 1, 2, 5, 3, 7,10, 9,12]
                   ^           ^ 
                  i=2         j=6
    
  2. in the subarray between these two indices, find the minimum and maximum elements

    min_ij([5, 3, 7,10, 9]) = 3
    max_ij([5, 3, 7,10, 9]) = 10
    
  3. if the minimum element of the subarray is greater than all elements before, you have found i (this is the case in your example). Else, update i to the index of the first element in the full array which is greater than min_ij.

  4. if the maximum element of the subarray is smaller than all elements after, then you have found j (this is the case in your example). Else, work backwards to update j to the index of the last element in the full array that is smaller than max_ij.

  5. compute the length as length = j - i + 1, which in your example would be length = 6 - 2 + 1 = 5.

buddemat
  • 4,552
  • 14
  • 29
  • 49