leetcode 209.長度最小的子陣列
阿新 • • 發佈:2018-12-16
1 題目描述
給定一個含有 n 個正整數的陣列和一個正整數 s ,找出該陣列中滿足其和 ≥ s 的長度最小的連續子陣列。如果不存在符合條件的連續子陣列,返回 0。
示例:
輸入: s = 7, nums = [2,3,1,2,4,3] 輸出: 2
解釋: 子陣列 [4,3] 是該條件下的長度最小的連續子陣列。 進階: 如果你已經完成了O(n) 時間複雜度的解法, 請嘗試 O(n log n) 時間複雜度的解法。
2 解法
在做862時無意中做出了這個題。它和862的區別是,陣列中的數都是正數。 在O(N)時間內計算nums的累積和陣列sums,sums[i]=nums[0]+nums[1]+…+nums[i]。 假設當前視窗為k,在O(n)時間內可以計算出所有視窗大小為k的子陣列的和,如果最大的比s小,要增大視窗,如果最大的比s大(或相等)就縮小視窗。這樣最多lg(n)次迴圈就可以了。
3 java原始碼
class Solution { // A的累計和陣列,sums[i] = sums(A[0]+A[1]+...+A[i]) int[] sums; int K; int[] A; int minWindownSize; /** * 視窗大小固定時,計算每個視窗內所有值的和,返回最大的和 * 時間複雜度為O(n) * * @param x 視窗大小 * @return 最大的視窗內值的和 */ private int maxSumOverFixedSizeWindow(int x) { int max = sums[x-1]; for (int i = 1; i < sums.length-x+1; i++) { int sum = sums[i+x-1]-sums[i-1]; if (sum > max) max = sum; } return max; } /** * 可能的視窗範圍在[min, max]之間,確定一箇中間的數,然後遞迴查詢 * @param min * @param max * @return */ private void find(int min, int max) { if (min > max) return; int x = (max-min)/2+min; // 視窗大小 if (minWindownSize > 0 && minWindownSize <= x) return; int maxSum = maxSumOverFixedSizeWindow(x); // 視窗大小為x時,視窗內值的和最大為maxSum if (maxSum < K) { // 擴大視窗,沒有找到,擴大視窗,看看能不能找到,可能會一直擴大到視窗為n, find(x+1, max); find(min, x-1); } else { // 縮小視窗 maxSum >= K,找到了,繼續尋找有沒有更好的,要一直縮小到視窗為1 minWindownSize = x; find(min, x-1); } } public int minSubArrayLen(int s, int[] nums) { int n = nums.length; if (n == 0) return 0; sums = new int[n]; sums[0] = nums[0]; for (int i = 1; i < n; i++) { sums[i] = sums[i-1]+nums[i]; } this.K = s; this.A = nums; this.minWindownSize = 0; for (int size = 1; size <= n; size*=2) { int maxSum = maxSumOverFixedSizeWindow(size); if (maxSum >= K) { minWindownSize = size; } } if (minWindownSize != 0) { find(1, minWindownSize); } else { find(1, n); } return this.minWindownSize; } }