• [LeetCode 1574] Shortest Subarray to be Removed to Make Array Sorted


    Given an integer array arr, remove a subarray (can be empty) from arr such that the remaining elements in arr are non-decreasing.

    A subarray is a contiguous subsequence of the array.

    Return the length of the shortest subarray to remove.

     

    Example 1:

    Input: arr = [1,2,3,10,4,2,3,5]
    Output: 3
    Explanation: The shortest subarray we can remove is [10,4,2] of length 3. The remaining elements after that will be [1,2,3,3,5] which are sorted.
    Another correct solution is to remove the subarray [3,10,4].

    Example 2:

    Input: arr = [5,4,3,2,1]
    Output: 4
    Explanation: Since the array is strictly decreasing, we can only keep a single element. Therefore we need to remove a subarray of length 4, either [5,4,3,2] or [4,3,2,1].
    

    Example 3:

    Input: arr = [1,2,3]
    Output: 0
    Explanation: The array is already non-decreasing. We do not need to remove any elements.
    

    Example 4:

    Input: arr = [1]
    Output: 0
    

     

    Constraints:

    • 1 <= arr.length <= 10^5
    • 0 <= arr[i] <= 10^9

    Before solving this problem, let's look at another problem that has a similar statement but requires a completely different algorithm to solve. 

    Locate smallest window to. be sorted: Given an array of integers that are possibly out of order, determine the bounds of the smallest window that must be sorted in order for the entire array to be sorted. For example, given[3,7,5,6,9], you should return [1,3]. 

    The sorting solution is pretty simple: creat a sorted copy of the original array then return the first and last altered element as the answer window. There is another 2-pass O(N) solution. 

    1. From left to right, keep a running maximum, and use the last element that is less than the running maximum as the right bound;

    2. From right to left, keep a running minimum, and use the last element that exceeds the running minimum as the left bound.

    The above problem's solution does not apply here with the intended problem. I went over it just because it occurred to me during the contest. Now let's solve the intended problem. 

    Solution that I came up during contest: Binary search on answer.

    If we can delete a subarray of length k to make the array sorted, then a longer length is also sufficient because removing elements from a sorted array preserves the sorted order. So we can binary search in range [0, N - 1] to find the smallest window to delete. If the middle range is sufficient, search on the left half including the middle size, otherwise search on the right half excluding the middle size. 

    It takes O(N) time to check for a given subarray length k by using the sliding window technique: 

    1. get the longest sorted subarry from right to left, if its length is already >= k, return true;

    2. otherwise from left to right, take 1 more element as long as the left subarray is sorted. If the left and right subarrays have >= k elements and the last element of the left subarray is <= the element at index k + left subarray's length, we've found a valid window to delete, return true. Why index k + left subarray's length? Let's denote the length of the left subarray as C1, all these elements are used, so the right subarray must be able to provide the last n - k - C1 elements. The starting index of such elements is n - (n - k - C1) = k + C1.

    3. at any point if we have not found a valid window to delete and the left subarray can not be extended further, return false as it is impossible to find such window of given length k.

    The runtime is O(N * log N).

    class Solution {
        public int findLengthOfShortestSubarray(int[] arr) {
            int n = arr.length, l = 0, r = n - 1;
            while(l < r - 1) {
                int mid = l + (r - l) / 2;
                if(check(arr, mid)) {
                    r = mid;
                }
                else {
                    l = mid + 1;
                }
            }
            if(check(arr, l)) {
                return l;
            }
            return r;
        }
        
        private boolean check(int[] a, int k) {
            int cnt1 = 0, cnt2 = 0, n = a.length, prev = Integer.MAX_VALUE;
            for(int i = a.length - 1; i >= k; i--) {
                if(a[i] <= prev) {
                    cnt2++;
                    prev = a[i];
                }
                else {
                    break;
                }
            }
            if(cnt2 == n - k) {
                return true;
            }
            prev = -1;
            //loop for window's start index
            for(int i = 0; i <= n - k; i++) {
                if(cnt1 == n - k) {
                    return true;
                }
                if(cnt1 + cnt2 >= n - k) {
                    if(k + cnt1 >= n - cnt2 && a[cnt1 - 1] <= a[k + cnt1]) {
                        return true;
                    }             
                }            
                if(prev > a[i]) {
                    break;
                }
                prev = a[i];
                cnt1++;
            }
            return false;
        }
    }

    After reading through other contestant's solution, I realized there is no need to binary search on the final answer. Instead we can just use the two pointers technique to find the best answer.

    1. Find the longest sorted subarray ending at the last element, denote r as the index of the first element of such subarray.

    2. From left to right, keep a running sorted subarray by adding one more element at a time if possible. As long as we can do this, we use all this left subarray and move r toward right to find the the longest sorted right subarray that can be appended to the running left subarray. 

    3. take the best answer from 1 and 2.

    The key here is that after deleting a subarray, there must be a left subarray and a right subarray. We then try out all possible left subarray ending positions and for each such position, we can the longest right subarray that can make the two subarrays sorted. The final answer must be the minimum of all possible cases.

    The runtime is O(N).

    class Solution {
        public int findLengthOfShortestSubarray(int[] arr) {
            int n = arr.length, l = 0, r = n - 1;
            for(; r > 0; r--) {
                if(arr[r - 1] > arr[r]) {
                    break;
                }
            }
            int ans = r - l;
            for(; l < r; l++) {
                if(l > 0 && arr[l - 1] > arr[l]) {
                    break;
                }
                while(r < n && arr[r] < arr[l]) {
                    r++;
                }
                ans = Math.min(ans, r - l - 1);
            }
            return ans;
        }
    }
  • 相关阅读:
    用PHP写一个代理来解决跨域问题
    curl
    centOS 安装及部署 SVN
    vue.js 安装
    谷歌开发者 代码调试同步本地文件功能
    Liunx 下的 SNMP 及 PHP如何连接
    2017年5月11日 开放大学 理财考试记
    js window.onlload 自遐想
    纯页面跳转问题
    mysql 字列问题
  • 原文地址:https://www.cnblogs.com/lz87/p/13630198.html
Copyright © 2020-2023  润新知