1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution { public int minSubArrayLen (int target, int [] nums) { int [] prefixSum = new int [nums.length]; prefixSum[0 ] = nums[0 ]; for (int i = 1 ; i < nums.length; i++) { prefixSum[i] = prefixSum[i - 1 ] + nums[i]; } int ans = Integer.MAX_VALUE; for (int i = 0 ; i < prefixSum.length; i++) { if (prefixSum[i] < target) continue ; int offset = prefixSum[i] - target; int leftBound = binarySearch(prefixSum, 0 , i - 1 , offset); ans = Math.min(ans, i - leftBound); } return ans == Integer.MAX_VALUE ? 0 : ans; } private int binarySearch (int [] prefixSum, int left, int right, int target) { int ans = -1 ; while (left <= right) { int mid = left + (right - left) / 2 ; if (prefixSum[mid] <= target) { ans = mid; left = mid + 1 ; } else { right = mid - 1 ; } } return ans; } }
prefix sum + binary search
时间复杂度: O(nlogn) 空间复杂度: O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int minSubArrayLen (int target, int [] nums) { int left = 0 , right = 0 , sum = 0 , ans = Integer.MAX_VALUE; while (right < nums.length) { while (right < nums.length && sum < target) { sum += nums[right]; right += 1 ; } if (sum < target) { break ; } while (left < right && sum >= target) { sum -= nums[left]; left += 1 ; } int currLength = right - left + 1 ; ans = Math.min(ans, currLength); } return ans == Integer.MAX_VALUE ? 0 : ans; } }
sliding window. left表示起点, right表示终点. 我们就开始移动right, 直到某个位置发现sum >= target, 我们停止. 当然right需要在nums的范围内移动. right停止后, 我们看一下当前sum是否大于等于target, 如果没有, 那么目前框起来的区域也累积不到target, 我们直接break. 如果可以, 那就说明在当前left的情况下, 最小的区域就是[left, right), 此时right再移动也没有必要因为在left开头的区域中, 此时是最小的. 此时我们移动left, 看能不能更小. 移动left的时候, sum在不断变小. 新left必须到达right这个位置(不包括right)才能大于等于target, 因为我们在旧left的时候尚且要到达right这个位置, 更何况新left的sum更小, 因此至少要到right. 于是我们移动left, 直到某个时刻, sum小于target了, 我们就知道此时位置的上一个即left - 1处到right构成的区域还是大于target的, 即区域[left - 1, right). 此时我们计算这个区域长度并记录到ans中. 接着我们继续移动right即可.
时间复杂度: O(n) 空间复杂度: O(1)