1574. 删除最短的子数组使剩余数组有序(二分)

给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。

一个子数组指的是原数组中连续的一个子序列。

请你返回满足题目要求的最短子数组的长度。

 

示例 1:

输入:arr = [1,2,3,10,4,2,3,5]
输出:3
解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5] 。
另一个正确的解为删除子数组 [3,10,4] 。

示例 2:

输入:arr = [5,4,3,2,1]
输出:4
解释:由于数组是严格递减的,我们只能保留一个元素。所以我们需要删除长度为 4 的子数组,要么删除 [5,4,3,2],要么删除 [4,3,2,1]。

示例 3:

输入:arr = [1,2,3]
输出:0
解释:数组已经是非递减的了,我们不需要删除任何元素。

示例 4:

输入:arr = [1]
输出:0

 

提示:

  • 1 <= arr.length <= 10^5
  • 0 <= arr[i] <= 10^9
 
 
其实这个题是考虑一下最终的状态:
1.删除前面的一段,后面的递增的全部保留
2.删除后面的一段,前面的递增的全部保留
3.删除中间的一段,然后删除的两端可以接上,使其剩下的都递增
 
首先我们先处理一个l,指的是从0到l是递增的,然后在处理一个r,指的是从r到n-1是递增的,然后我们可以遍历这个r到n-1中的i,然后在0到l中找比a[i]小的那个下标,更新答案
当然也可以用双指针
class Solution {
public:
    int findLengthOfShortestSubarray(vector<int>& arr) {
        int i, j, size = arr.size();

        //数组长度为0或者为1时,不需要删除任何元素。
        if(size <= 1) return 0;

        //数组长度大于1时,先确定左右的非递减子序列,获得其index,记为i和j。
        for(i = 0; i < size - 1; i++) if(arr[i] > arr[i + 1]) break;
        if(i == size - 1) return 0;
        for(j = size - 1; j > 0; j--) if(arr[j] < arr[j - 1]) break;

        //比对arr[i]和arr[j],如果arr[i]到arr[j]是非递减的,那么就删去i和j之间的元素。
        if(arr[i] <= arr[j]) return j - i - 1;
        else {
            //min的初始值设为完全删去左子序列以外的所有元素和完全删去右子序列以外的所有元素二者中的最小者。
            int k, min = (size - i - 1 > j ? j : size - i - 1);
            for(k = 0; k <= i; k++) {
                //对于index为0到i中的每个元素,找到index为j到最末这段子序列中第一个大于它的元素的index,然后再与当前的min比对。
                int nextIndex = findNextIndex(arr, j, size - 1, arr[k]);
                if(min > nextIndex - k - 1) min = nextIndex - k - 1;
            }
            return min;
        }
    }

    //利用二分法,找到index为start和end之间,刚好大于data的元素。
    int findNextIndex(vector<int>& arr, int start, int end, int data) {
        if(start == end) {
            if(arr[start] >= data) return start;
            else return start + 1;
        }
        int mid = (start + end) / 2;
        if(arr[mid] >= data) return findNextIndex(arr, start, mid, data);
        else return findNextIndex(arr, mid + 1, end, data);
    }
};

 

 

class Solution {
public:
    int findLengthOfShortestSubarray(vector<int>& arr) {
        if (arr.size() < 2) {
            return 0;
        }

        int N = arr.size();
        int left = 0;
        while (left < N - 1 && arr[left] <= arr[left + 1]) {
            left++;
        }

        if (left == N - 1) {
            return 0;
        }

        int right = N - 1;
        while (right > 0 && arr[right] >= arr[right - 1]) {
            right--;
        }

        int res = min((N - 1) - (left + 1) + 1, /* delete [left + 1, N - 1] */
                      right /* delete [0, right - 1]*/);

        int i = 0;
        int j = right;
        while (i <= left && j <= N - 1) {
            if (arr[i] <= arr[j]) {
                // sorted left and right, but not middle [i + 1, j - 1]
                res = min(res, j - i - 1);
                i++; // don't forget to update i
            } else {
                // cannot update since left and right are not sorted together
                j++;
            }
        }
        
        return res;
    }
};

 

posted @ 2021-06-18 00:23  lipu123  阅读(326)  评论(0)    收藏  举报