给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出: 2 解释: 子数组[4,3]
是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
//章节 - 数组和字符串 //四、双指针技巧 //6.长度最小的子数组 /* 算法思想: 一个不高效的解法,需要定义两个指针left和right,分别记录子数组的左右的边界位置,然后我们让right向右移,直到子数组和大于等于给定值或者right达到数组末尾,此时我们更新最短距离,并且将left像右移一位,然后再sum中减去移去的值,然后重复上面的步骤,直到right到达末尾,且left到达临界位置,即要么到达边界,要么再往右移动,和就会小于给定值。 */ //算法实现: // O(n) /* class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { int res = INT_MAX, left = 0, sum = 0; for (int i = 0; i < nums.size(); ++i) { sum += nums[i]; while (left <= i && sum >= s) { res = min(res, i - left + 1); sum -= nums[left++]; } } return res == INT_MAX ? 0 : res; } }; */ /* 算法思想: 一个高效的解法,需要用到二分查找法,思路是,我们建立一个比原数组长一位的sums数组,其中sums[i]表示nums数组中[0, i - 1]的和,然后我们对于sums中每一个值sums[i],用二分查找法找到子数组的右边界位置,使该子数组之和大于sums[i] + s,然后我们更新最短长度的距离即可。 */ //算法实现: // O(nlgn) class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { int len = nums.size(), sums[len + 1] = {0}, res = len + 1; for (int i = 1; i < res; ++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; } 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; } };