【LeetCode】209. 長度最小的子數組

209. 長度最小的子數組

知識點:數組;前綴和;二分查找;雙指針;滑動窗口java

題目描述

給定一個含有 n 個正整數的數組和一個正整數 target 。數組

找出該數組中知足其和 ≥ target 的長度最小的 連續子數組 [numsl, numsl+1, ..., numsr-1, numsr] ,並返回其長度。若是不存在符合條件的子數組,返回 0 。指針

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

輸入:target = 4, nums = [1,4,4]
輸出:1

輸入:target = 11, nums = [1,1,1,1,1,1,1,1]
輸出:0

解法一:暴力法

使用兩層for循環遍歷,找到最大子長度;code

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

時間複雜度:0(N^2);leetcode

解法二:前綴和+二分查找

這道題一看連續子數組觸發了前綴和,前綴和就是用來解決連續子數組問題的,因此能夠先統計到達每一個的前綴和,仍然是爲了方便,建立長度是n+1的數組,第一個位置放0,這樣最後輸出子數組長度的時候不用再去+1了,直接j-i就能夠了。
前綴和以後,要想尋找子數組和大於target,就是找sum[i]-sum[j] >= target, 仍然須要遍歷兩遍,可是前綴和數組有一個重要的特色,就是是遞增的(由於只有正數),因此這時候能夠用二分搜索,將複雜度下降到O(logN),咱們就是想找大於等於sum[j]+target的值.
在java中Arrays類有能夠直接調用的Arrays.binarySearch(數組,目標值);若是能找到,就返回找到值的下標,若是沒找到就返回一個負數,這個負數取反以後就是查找的值應該在原數組中的位置。get

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int minLen = Integer.MAX_VALUE;
        int[] presum = new int[nums.length+1]; //第一位放0;
        for(int i = 1; i < presum.length; i++){
            presum[i] = presum[i-1]+nums[i-1];  //前綴和數組;表示到i以前的全部和,不包括i
        }
        for(int i = 0; i < nums.length; i++){
            int t = target+presum[i];
            int index = Arrays.binarySearch(presum, t);  //二分查找;
            if(index < 0) index = ~index;   //沒找到的話就取反返回應該插入的位置;
            if(index <= nums.length){
                minLen = Math.min(minLen, index-i);
            }
        }
        return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }
}

時間複雜度:0(NlogN);io

解法三:滑動窗口

滑動窗口其實就是雙指針的一種,只不過在移動過程當中像是一個窗口在移動,因此稱做滑動窗口,這是解決連續數組中一個很常見的思路;for循環

能夠定義兩個指針start和end(分別表示窗口的開始和結束),end從頭至尾去遍歷數組,當移動出去以後遍歷結束。在過程當中,將nums[end]不斷的加到sum上,若是sum>= target, 那就更新數組的最小長度,而後將nums[stat]在sum中減去,start前移,直到sum< target後,end再移;class

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int minLen = Integer.MAX_VALUE;
        int left= 0, right = 0;
        int sum = 0;
        while(right < nums.length){
            sum += nums[right];
            while(sum >= target){
                minLen = Math.min(minLen, right-left+1);
                sum -= nums[left]; //窗口移動,減去出窗口的值;
                left++;
            }
            right++;
        }
        return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }
}

體會

連續子數組+和 --> 前綴和
連續子串+最值 --> 滑動窗口搜索

相關連接

長度最小的子數組-看滑動窗口
長度最小的子數組-看前綴和

相關文章
相關標籤/搜索