https://leetcode.cn/problems/minimum-size-subarray-sum/description/

<aside> 💡

思路重点:使用right作为循环条件,对于每个确定的right,移动left寻找该right值下的最优解(滑动窗口)

注意:left不用每次都从第一个开始重新遍历,而是接着上一次的位置往后走,所以实际上left和right各自都只遍历了一遍数组,时间复杂度是n+n,即O(n),而非O(n^2)

</aside>

v1

// 维护两个指针,总和大于target则从左缩减范围,小于target则从右扩大范围
// 使用一个值ans来记录滑动过程中发现的最小长度
int minSubArrayLen0(int target, vector<int>& nums) {
	int left = 0, right = 0; 
	int sum;
	int ans = nums.size() + 1;
	if (nums.size() > 0)
		sum = nums[0];
	else
		return 0;

	while (right <= nums.size() - 1) {
		// right达到边界时,left还有缩减的可能
		if (right == nums.size() - 1 && sum < target)
			break;
		if (sum < target) {
			// 扩展右侧
			sum += nums[++right];
		} else {
			// 更新最小长度
			ans = ((right - left + 1) < ans) ? (right - left + 1) : ans;
			// 缩减左侧
			sum -= nums[left++];	
		}
	}
	return (ans == nums.size() + 1) ? 0 : ans;
}

v2——先扩张窗口再收缩窗口,

int minSubArrayLen(int target, vector<int>& nums) {
    int left = 0;
    int right = 1;
    int sum = nums[0];
    if (sum >= target) {
        return 1;
    }
    int ans = nums.size() + 1;

    // 窗口左闭右开
    while (right < nums.size()) {
        // 从右侧扩大窗口,right到达边界时只能进行收缩窗口操作
        while (right < nums.size() && sum < target) {
            sum += nums[right++];
        }
        // 从左侧收缩窗口
        while (left < right && sum >= target) {
            ans = std::min(ans, right - left);
            sum -= nums[left++];
        }
    }
    return (ans == nums.size() + 1) ? 0 : ans;
}

v3优化版——固定right,寻找当前right下的最优left

// 看代码随想录视频讲解改进后的写法
int minSubArrayLen(int target, vector<int>& nums) {
	int left = 0, right = 0;
	int sum = 0;
	int ans = nums.size() + 1;

	for (; right <= nums.size() - 1; ++right) {
		sum += nums[right];

		// 移动left,寻找right当前位置的最优解
		while (sum >= target) {
			ans = ((right - left + 1) < ans) ? (right - left + 1) : ans;
			sum -= nums[left++];
		}
	}
	return (ans == nums.size() + 1) ? 0 : ans;
}