1.长度最小的子数组
题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
解法⼀:暴力求解(会超时)
算法思路:
「从前往后」枚举数组中的任意⼀个元素,把它当成起始位置。然后从这个「起始位置」开始,然后寻找⼀段最短的区间,使得这段区间的和「⼤于等于」⽬标值。
将所有元素作为起始位置所得的结果中,找到「最⼩值」即可。
算法代码:
// 枚举所有可能的起始位置
for (int start = 0; start < n; ++start) {
int sum = 0;
// 从 start 开始扩展子数组,直到和满足条件
for (int end = start; end < n; ++end) {
sum += nums[end];
if (sum >= target) {
// 以 start 开头的最短子数组已经找到
result = min(result, end - start + 1);
break;
}
}
}
// 若没有符合条件的子数组,返回 0
return result == INT_MAX ? 0 : result;
}
解法二(滑动窗口及同向双指针):
算法思路:
本题求解的对象是一段连续的区间,因此可以借助滑动窗口的思想来处理。我们让滑动窗口始终满足:从位置 i 开始,窗口内所有元素之和小于 target。这样一来,当窗口内元素之和第一次大于等于目标值时,就得到了以 i 为起点、满足条件的最短子数组长度。
具体做法:不断将右端元素划入窗口,并统计当前窗口内元素的总和:
▪ 如果窗口内元素之和大于等于 target:更新结果,同时将左端元素划出窗口,并继续判断是否仍满足条件、继续更新结果(因为左端元素可能很小,划出之后窗口内元素之和依然满足条件)。
▪ 如果窗口内元素之和仍不满足条件:执行 right++,让下一个元素进入窗口。
C++算法代码:

时间复杂度:虽然代码是两层循环,但 left 指针和 right 指针都是不回退的,两者最多都往后移动 n 次,因此时间复杂度是 O(N)。
2.将x减到0的最小操作数(medium)
题目链接:1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)
题目分析:
我们发现如果直接按要求来解题是很困难的,情况十分复杂。因此正难则反,我们可以换一种思考方式,若从两边下手难我们可以从中间下手,我们可以转化成求数组内⼀段连续的、和为 sum(nums) - x 的最⻓数组。此时,就是熟悉的「滑动窗⼝」问题了。
算法流程:
a.令 target = sum(nums) - x。若 target < 0,则问题无解;
b. 初始化左右指针 l = 0, r = 0(滑动窗口区间为 [l, r),必须明确左闭右开,确保与代码一致);用变量 sum 记录当前窗口内数组元素之和,初值为 0;用 maxLen 记录当前满足条件的数组最大区间长度,初值为 -1;
c. 当 r 小于等于数组长度时,持续循环:
i. 若 sum < target,右移右指针,直到变量和大于等于 target,或右指针已到达末尾;
ii. 若 sum > target,右移左指针,直到变量和小于等于 target,或左指针已到达末尾;
iii. 如果经过上述两步调整后 sum == target,则更新满足条件的最大区间长度,并让下一个元素进入窗口;
d. 循环结束后,若 maxLen 具有有效值,则返回对应计算结果;否则返回 -1。
C++算法代码:

注意left越界问题