09. 长度最小的子数组
题目描述: 给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组 [numsl, numsl+1, ..., numsr-1, numsr],并返回其长度。如果不存在符合条件的子数组,返回 0。
解法一:暴力求解
枚举数组中的任意元素作为起始位置,向后寻找一段最短的区间使得和大于等于目标值。虽然逻辑直观,但时间复杂度为 O(N²),在数据量较大时容易超时。
解法二:滑动窗口
核心在于维护一个满足条件的连续区间。右指针不断扩张窗口累加 sum,一旦 sum >= target,左指针开始收缩以寻找更短的有效长度。
为什么滑动窗口效率高? 这里想多聊两句原理。很多教程只给结论,但理解'为什么'才能举一反三。这个窗口寻找的是:以当前窗口最左侧元素为基准,符合条件的情况。既然已经找到从 left1 开始的最优区间,就可以大胆舍去 left1。继续像方法一一样重新统计会有大量重复计算。此时 right1 的作用体现出来了,我们只需要将 left1 的值从 sum 中剔除,从 right1 开始往后找满足条件的区间。这样能省掉大量重复计算。
左右指针均不回退,每个元素最多进出一次窗口,总操作次数为 2N,因此时间复杂度降为 O(N)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size(), sum = 0, len = INT_MAX;
for (int left = 0, right = 0; right < n; right++) {
sum += nums[right];
while (sum >= target) {
len = min(len, right - left + 1);
sum -= nums[left++];
}
}
return len == INT_MAX ? 0 : len;
}
};
10. 无重复字符的最长子串
题目描述: 给定一个字符串 s,请你找出其中不含有重复字符的最长子串的长度。
解法一:暴力求解
从每一个位置开始往后扫描,利用哈希表统计字符频次,直到发现重复元素停止。虽然可以通过测试用例,但效率并非最优。
解法二:滑动窗口 + 哈希表
同样维护一个无重复字符的窗口。右指针加入字符,若该字符频次超过 1,则左指针移动直至重复消除,同时更新最大长度。
实现细节: 由于字符集有限(ASCII),可用定长数组模拟哈希表,比 unordered_map 更快且更稳定。当 hash[s[right]] > 1 时,说明窗口内有重复,需要收缩左边界直到该字符频次变回 1。
class Solution {
:
{
hash[] = {};
left = , right = , ret = ;
n = s.();
(right < n) {
hash[s[right]]++;
(hash[s[right]] > ) {
hash[s[left++]]--;
}
ret = (ret, right - left + );
right++;
}
ret;
}
};


