知識點:數組;前綴和;二分查找;雙指針;滑動窗口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; } }
連續子數組+和 --> 前綴和
連續子串+最值 --> 滑動窗口搜索