// 队列滑窗法
// 要解题,先怎么简单怎么来。
// 定义一个队列q(LinkedList来模拟),定义sum变量来记录队列窗口q中元素的
// 和。我们用队列q来模拟我们要的连续子数组,遍历到的元素存入q中,并记录q
// 元素的和sum,如果sum大于等于target,则贪心地将q.size()和答案保存位res
// (初始化为Integer.MAX_VALUE)中最小的那个更新给res。然后将q的队列头(
// 最早入队的)元素删除。删除队列头元素之后sum值还有可能大于等于target,
// 删完之后还不能走,所以用一个while子循环嵌套一下,如果删除队列头元素
// 之后sum值还大于等于target,且q不为空,那继续将贪心地将q.size()和答案保
// 存位res中最小的那个更新给res。
//
// 执行用时:6 ms, 在所有 Java 提交中击败了20.22%的用户
// 内存消耗:39.4 MB, 在所有 Java 提交中击败了5.00%的用户
class Solution {
public int minSubArrayLen(int target, int[] nums) {
LinkedList<Integer> q = new LinkedList<>();
int res = Integer.MAX_VALUE;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
q.add(nums[i]);
sum += nums[i];
while (!q.isEmpty() && sum >= target) {
res = Math.min(res, q.size());
sum -= q.removeFirst();
}
}
return (res == Integer.MAX_VALUE) ? 0 : res;
}
}
// 双指针滑窗法
// 其实想到双指针法但是不知道怎么实现的,等写出来队列滑窗法之后,自然就知道
// 了。改一改就是双指针法,left指针是队列窗口的左边界,right指针是队列窗口
// 的右边界,这里的right跟队列划窗法for循环中的i是一样的,只是这里不需要
// 把元素存入q中了,直接将遍历到的nums[right]累加给sum,而while子循环中
// 的q不为空要改为left <= right,这里允许left和right相遇的情况,相遇时相当
// 与窗口中只有一个元素。q.size()改为right-left+1,窗口左元素(队列头元素)
// 删除掉之后,left手动右移。
//
// 执行用时:2 ms, 在所有 Java 提交中击败了83.69%的用户
// 内存消耗:38 MB, 在所有 Java 提交中击败了98.32%的用户
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int sum = 0;
int left = 0;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (left <= right && sum >= target) {
res = Math.min(res, right - left + 1);
sum -= nums[left++];
}
}
return (res == Integer.MAX_VALUE) ? 0 : res;
}
}