LeetCode 1574. Shortest Subarray to be Removed to Make Array Sorted

96 阅读2分钟

🔗 leetcode.com/problems/sh…

题目

  • 给定一个数组,删除连续子序列后,剩下的元素非降序
  • 求要删除的连续子序列的最小长度

思路

  • 找到包含开头的非降序子序列,找到包含结尾的非降序子序列,拼接形成最长非降序子序列,中间的就是要删除掉的子序列

  • 最近一直做二分,先用了二分的思路,性能仅打败 25%,后面改成了 two pointer

  • 二分的思路

    • 找到从头开始的非降序连续子序列 0 ~ prefix_index,找到包含结尾的非降序连续子序列,suffix_index ~ arr.size -1,尝试拼接
    • 遍历 j suffix_index ~ arr.size -1,用二分找到 i 0 ~ prefix_index 中,arr[i] ≤ arr[j] 的 i 的最大值
    • 更新尝试拼接后的最长非降序子序列的长度,记录最大值
  • two pointer

    • 拼接的时候,用 two pointer 遍历即可,i 是包含开头的 index,j 是包含结尾的 index,因为拼接需要严格要求 arr[i] ≤ arr[j] 且 arr[i] ≤ arr[i+1] 时 i++,所以 i 和 j 的 ++,可以保证遍历出所有可能性

代码

class Solution {
public:
    int upper_bound(int num, int r, vector<int>& arr) {
        if (arr[0] > num) return -1;
        int l = 0;
        while (l < r) {
            int mid = ((l + r) >> 1) + ((l + r) & 1);
            if (arr[mid] > num) r = mid -1;
            else l = mid;
        }
        return l;
    }
    int solution1(vector<int>& arr) { // o nlogn
        int size = arr.size();
        int prefix_index = 0;
        for (int i = 1; i < size; i++) {
            if (arr[i-1] <= arr[i]) prefix_index++;
            else break;
        }
        int suffix_index = size - 1;
        for (int i = size - 2; i >= 0; i--) {
            if (arr[i] <= arr[i+1]) suffix_index--;
            else break;
        }
        if (prefix_index >= suffix_index) return 0;
        //printf("prefix_index %d suffix_index %d\n", prefix_index, suffix_index);
        int ans = max(prefix_index + 1, size - suffix_index);
        for (int i = suffix_index; i < size; i++) {
            int index = upper_bound(arr[i], prefix_index, arr);
            //printf("arr[i] %d index %d\n", arr[i], index);
            ans = max(ans, size - i + index + 1);
        }
        return size - ans;
        
    }
    int solution2(vector<int>& arr) { // two pointer o n
        int suffix_prefix = arr.size() - 1;
        for (int i = arr.size()-2; i >= 0; i--) {
            if (arr[i] <= arr[i+1]) suffix_prefix--;
            else break;
        }
        int ans = suffix_prefix;
        if (ans == 0) return 0;
        int i = 0, j = suffix_prefix, size = arr.size();
        for (int i = 0; i < suffix_prefix; i++) {
            while (j < size && arr[i] > arr[j]) {
                j++;
            }
            if (j >= size) ans = min(ans, size - i);
            ans = min(ans, j - i -1);
            if (arr[i] > arr[i+1]) break;
        }
        return ans;
    }
    int findLengthOfShortestSubarray(vector<int>& arr) {
        //return solution1(arr);
        return solution2(arr); 
    }

};