Given an integer array arr
, your task is to find the length of the shortest subarray that can be removed so that the remaining elements of arr
are in non-decreasing order. In other words, after you remove a contiguous subarray (possibly empty), the rest of the array should be sorted in ascending order (with duplicates allowed).
Example:
Input: arr = [1,2,3,10,4,2,3,5]
Output: 3
Explanation: Remove the subarray [10,4,2]
to get [1,2,3,3,5]
which is non-decreasing.
The naive approach might be to consider every possible subarray and check if removing it makes the array sorted. However, this is too slow for large arrays. Instead, let's rethink the problem:
Here's how we can efficiently solve the problem step-by-step:
left
be the last index of this prefix.
right
be the first index of this suffix.
right - left - 1
.
i
in the prefix (from 0 to left
), use binary search to find the smallest index j
in the suffix (from right
to end) such that arr[i] ≤ arr[j]
. The subarray to remove is from i+1
to j-1
.
We use binary search for efficiency, as the suffix is sorted.
Let's use the sample input arr = [1,2,3,10,4,2,3,5]
:
[1,2,3,10]
is non-decreasing (indices 0-3).
[2,3,5]
is non-decreasing (indices 5-7).
[4]
(removes just 4). Remaining: [1,2,3,10,2,3,5]
(not sorted).[4,2]
. Remaining: [1,2,3,10,3,5]
(not sorted).[10,4,2]
. Remaining: [1,2,3,3,5]
(sorted).The key insight is that we don't need to check every possible subarray. By focusing on the longest sorted prefix and suffix, and efficiently merging them using binary search, we can quickly find the shortest subarray to remove. This approach is both elegant and efficient, leveraging properties of sorted arrays and search algorithms.
class Solution:
def findLengthOfShortestSubarray(self, arr):
n = len(arr)
left = 0
while left + 1 < n and arr[left] <= arr[left + 1]:
left += 1
if left == n - 1:
return 0
right = n - 1
while right > 0 and arr[right - 1] <= arr[right]:
right -= 1
res = min(n - left - 1, right)
i = 0
j = right
while i <= left and j < n:
if arr[i] <= arr[j]:
res = min(res, j - i - 1)
i += 1
else:
j += 1
return res
class Solution {
public:
int findLengthOfShortestSubarray(vector<int>& arr) {
int n = arr.size();
int left = 0;
while (left + 1 < n && arr[left] <= arr[left + 1]) left++;
if (left == n - 1) return 0;
int right = n - 1;
while (right > 0 && arr[right - 1] <= arr[right]) right--;
int res = min(n - left - 1, right);
int i = 0, j = right;
while (i <= left && j < n) {
if (arr[i] <= arr[j]) {
res = min(res, j - i - 1);
i++;
} else {
j++;
}
}
return res;
}
};
class Solution {
public int findLengthOfShortestSubarray(int[] arr) {
int n = arr.length;
int left = 0;
while (left + 1 < n && arr[left] <= arr[left + 1]) left++;
if (left == n - 1) return 0;
int right = n - 1;
while (right > 0 && arr[right - 1] <= arr[right]) right--;
int res = Math.min(n - left - 1, right);
int i = 0, j = right;
while (i <= left && j < n) {
if (arr[i] <= arr[j]) {
res = Math.min(res, j - i - 1);
i++;
} else {
j++;
}
}
return res;
}
}
var findLengthOfShortestSubarray = function(arr) {
const n = arr.length;
let left = 0;
while (left + 1 < n && arr[left] <= arr[left + 1]) left++;
if (left === n - 1) return 0;
let right = n - 1;
while (right > 0 && arr[right - 1] <= arr[right]) right--;
let res = Math.min(n - left - 1, right);
let i = 0, j = right;
while (i <= left && j < n) {
if (arr[i] <= arr[j]) {
res = Math.min(res, j - i - 1);
i++;
} else {
j++;
}
}
return res;
};