1、附上题目链接
-
滑动窗口 思想(一般用于求最小值):
209. 长度最小的子数组
713. 乘积小于K的子数组
862. 和至少为 K 的最短子数组 -
前缀和 思想(一般用于求和):
560. 和为K的子数组
523. 连续的子数组和 -
动态规划 思想(一般用于求最大值):
718. 最长重复子数组
剑指 Offer 42. 连续子数组的最大和
152. 乘积最大子数组
2、代码关键点详解
2.1 关键点:滑动窗口 思想
2.1.1 长度最小的子数组
class Solution {
public int minSubArrayLen(int s, int[] nums) {
// 滑动窗口
int left = 0, right = 0;
int minLen = Integer.MAX_VALUE;
int sum = 0;
while (right < nums.length) {
sum += nums[right];
right++;
while(left < nums.length && sum >= s) {
minLen = Math.min(minLen, right - left); // 更新
sum -= nums[left];
left++;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
关键点1:滑动窗口
- 注意:涉及到连续子数组的题,要优先考虑滑动窗口思想。由于数组中的元素都为正数,所以可以直接用滑动窗口。若数组中含有负数,需要先计算前缀和,在采用滑动窗口思想。
关键点2:不存在符合条件的子数组,返回 0
return minLen == Integer.MAX_VALUE ? 0 : minLen;
2.1.2 乘积小于K的子数组
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
if (k == 0) return 0;
int res = 0;
int left = 0, right = 0;
int mul = 1; // 乘积
while (right < nums.length) {
mul *= nums[right];
right++;
while (left < right && mul >= k) {
mul = mul / nums[left];
left++;
}
res += (right - left); // 更新结果值
}
return res;
}
}
关键点1:算法流程
- 我们使用一重循环枚举 right,同时设置 left 的初始值为 0。
- 在循环的每一步中,表示 right 向右移动了一位,将乘积乘以 nums[right]。
- 此时我们需要向右移动 left,直到满足乘积小于 k 的条件。
- 在每次移动时,需要将乘积除以 nums[left]。
- 当 left 移动完成后,对于当前的 right,就包含了 right−left+1 个乘积小于 k 的连续子数组。
2.1.3 和至少为 K 的最短子数组
class Solution {
public int shortestSubarray(int[] A, int K) {
/*
滑动窗口:
1.当前元素小于队尾,队尾弹出
2.当前