1. 程式人生 > >領扣-209 長度最小的子數組 Minimum Size Subarray Sum MD

領扣-209 長度最小的子數組 Minimum Size Subarray Sum MD

二分查找 -m 子數組 雙指針法 amp 滿足 android tco 成了

目錄

  • 長度最小的子數組 Minimum Size Subarray Sum -209
    • 問題
    • 暴力法
    • 暴力法稍加改進(然並卵)
    • 雙指針法(推薦)
    • 二分查找法(不懂)
Markdown版本筆記 我的GitHub首頁 我的博客 我的微信 我的郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 [email protected]

領扣-209 長度最小的子數組 Minimum Size Subarray Sum MD
***
目錄
===

長度最小的子數組 Minimum Size Subarray Sum -209

問題

給定一個含有 n 個正整數的數組和一個正整數 s ,找出該數組中滿足其和 ≥ s

長度最小的連續子數組。如果不存在符合條件的連續子數組,返回 0

示例:

輸入: s = 7, nums = [2,3,1,2,4,5]
輸出: 2
解釋: 子數組 [4,5] 是該條件下的長度最小的連續子數組。

進階:
如果你已經完成了 O(n) 時間復雜度的解法, 請嘗試 O(n log n) 時間復雜度的解法。

暴力法

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int len = Integer.MAX_VALUE, tem;
        for (int i = 0; i < nums.length; i++) {
            tem = 0;
            for (int j = i; j < nums.length; j++) {
                tem += nums[j];
                if (tem >= s) {
                    len = Math.min(len, j - i + 1);
                    break;
                }
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

時間復雜度:O(n^2)
空間復雜度:O(1)

暴力法稍加改進(然並卵)

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int len = Integer.MAX_VALUE, tem;
        for (int i = 0; i < nums.length; i++) {
            tem = 0;
            for (int j = i; j < nums.length && j < i + len - 1; j++) {
                tem += nums[j];
                if (tem >= s) {
                    len = j - i + 1;
                    break;
                }
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

時間復雜度:O(n^2)
空間復雜度:O(1)

雙指針法(推薦)

我們需要定義兩個指針left和right,分別記錄子數組的左右的邊界位置,然後我們讓right向右移,直到子數組和大於等於給定值或者right達到數組末尾,此時我們更新最短距離,並且將left向右移一位,然後再sum中減去移去的值,然後重復上面的步驟,直到right到達末尾,且left到達臨界位置,即要麽到達邊界,要麽再往右移動,和就會小於給定值

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int len = Integer.MAX_VALUE, left = 0, sum = 0;
        for (int right = 0; right < nums.length; right++) {
            sum += nums[right]; //左指針不動,右指針一直向右移動
            while (sum >= s) {
                len = Math.min(len, right - left + 1); //當滿足條件時先記錄一下當前需要的長度
                sum -= nums[left++]; //然後左指針向右移動(移動過程中如果滿足條件則長度-1),直到不滿足條件(繼續移動右指針)
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

時間復雜度:O(n)
空間復雜度:O(1)

二分查找法(不懂)

思路是,我們建立一個比原數組長一位的sums數組,其中sums[i]表示nums數組中[0, i - 1]的和,然後我們對於sums中每一個值sums[i],用二分查找法找到子數組的右邊界位置,使該子數組之和大於sums[i] + s,然後我們更新最短長度的距離即可。

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int len = nums.length, res = len + 1;
        int[] sums = new int[len + 1];
        for(int i = 1; i<len+1; i++){
            sums[i] = sums[i-1] + nums[i-1];
        }
        for(int i = 0; i<len+1; i++){
            int right = searchRight(i+1, len, sums[i]+s, sums);
            if(right == len + 1) break;
            if(res > right - i) res = right - i;
        }
        return res == len + 1?0:res;
    }

    private int searchRight(int left, int right, int key, int sums[]){
        while(left <= right){
            int mid = (left + right)/2;
            if(sums[mid] >= key){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}

2018-12-16

領扣-209 長度最小的子數組 Minimum Size Subarray Sum MD