【算法题】滑动窗口(一)

滑动窗口是处理子串/子数组问题的经典双指针技巧,核心是通过维护一个"窗口"(左右指针界定的区间),动态调整窗口范围来满足题目条件,从而高效求解问题。

一、无重复字符的最长子串

题目描述:

给定一个字符串 s,找出其中不含有重复字符的最长子串的长度。

示例

  • 输入:s = "abcabcbb",输出:3(最长子串为 "abc"
  • 输入:s = "bbbbb",输出:1(最长子串为 "b"

解题思路:

用滑动窗口维护"无重复字符的子串",配合哈希数组记录字符出现次数:

  1. 定义窗口左右指针 leftright,哈希数组 hash[128] 统计窗口内字符出现次数。
  2. 右指针 right 遍历字符串,将当前字符加入窗口并更新出现次数。
  3. 若当前字符出现次数超过1(窗口内有重复),移动左指针缩小窗口,直到无重复。
  4. 每次调整后,更新最长子串长度。

完整代码:

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128] = {0};
        int ret = 0;
        for(int left = 0, right = 0; right < s.size(); right++) {
            hash[s[right]]++;
            while(hash[s[right]] > 1) {
                hash[s[left++]]--;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),每个字符最多被左右指针各遍历一次。
  • 空间复杂度:O(1)O(1)O(1),哈希数组大小固定(128个ASCII字符)。

二、长度最小的子数组

题目描述:

给定含 n 个正整数的数组和正整数 target,找出总和≥target的长度最小的子数组,返回其长度;若不存在则返回 0

示例

  • 输入:target = 7, nums = [2,3,1,2,4,3],输出:2(子数组 [4,3]

解题思路:

用滑动窗口维护"总和≥target的子数组",动态缩小窗口找最小长度:

  1. 定义窗口左右指针 leftright,变量 sum 记录窗口内元素和。
  2. 右指针 right 遍历数组,累加元素和到 sum
  3. sum ≥ target,尝试移动左指针缩小窗口(同时更新最小长度),直到 sum < target
  4. 遍历结束后,若未找到符合条件的子数组则返回 0

完整代码:

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, len = INT_MAX;
        for(int left = 0, right = 0; right < nums.size(); right++) {
            sum += nums[right];
            while(sum >= target) {
                len = min(len, right - left + 1);
                sum -= nums[left++];
            }
        }
        return len == INT_MAX ? 0 : len;
    }
};

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),每个元素最多被左右指针各遍历一次。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

三、最大连续1的个数 III

题目描述:

给定二进制数组 nums 和整数 k,最多可以翻转 k0,返回操作后数组中连续 1 的最大个数。

示例

  • 输入:nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2,输出:6(翻转后最长子数组为 [1,1,1,0,0,1,1,1,1,1]

解题思路:

用滑动窗口维护"最多包含 k0 的子数组"(即允许翻转 k0 后的连续1区间):

  1. 定义窗口左右指针 leftright,变量 zeros 统计窗口内 0 的个数。
  2. 右指针 right 遍历数组,遇到 0zeros++
  3. zeros > k,移动左指针缩小窗口,直到 zeros ≤ k
  4. 每次调整后,更新最长子数组长度。

完整代码:

cpp 复制代码
class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int ret = 0;
        for(int left = 0, right = 0, zeros = 0; right < nums.size(); right++) {
            if(nums[right] == 0) zeros++;
            while(zeros > k) {
                if(nums[left++] == 0) zeros--;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),每个元素最多被左右指针各遍历一次。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

四、将x减到0的最小操作数

题目描述:

给定整数数组 nums 和整数 x,每次操作移除数组最左或最右元素并从 x 中减去该元素值,要求将 x 恰好减到 0,返回最小操作数;否则返回 -1

示例

  • 输入:nums = [1,1,4,2,3], x = 5,输出:2(移除后两个元素 2+3=5

解题思路:
转化问题 :"最小操作数"等价于"数组中最长的、和为 sum(nums)-x 的子数组"(因为移除的元素是数组两端,剩余的中间子数组和为 sum-x)。

  1. 计算数组总和 sum,目标子数组和为 target = sum - x(若 target < 0,直接返回 -1)。
  2. 用滑动窗口找最长的、和为 target 的子数组。
  3. 若找到该子数组,最小操作数为 数组长度 - 子数组长度;否则返回 -1

完整代码:

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int sum = 0;
        for(auto n : nums) sum += n;
        int target = sum - x;
        if(target < 0) return -1;
        
        int ret = -1;
        for(int left = 0, right = 0, tmp = 0; right < nums.size(); right++) {
            tmp += nums[right];
            while(tmp > target) tmp -= nums[left++];
            if(tmp == target)
                ret = max(ret, right - left + 1);
        }
        return ret == -1 ? -1 : nums.size() - ret;
    }
};

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),每个元素最多被左右指针各遍历一次。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。
相关推荐
AuroraWanderll2 小时前
C++面向对象与类和对象(一)----C++重要基础入门知识
c语言·数据结构·c++·算法·stl
sali-tec10 小时前
C# 基于halcon的视觉工作流-章66 四目匹配
开发语言·人工智能·数码相机·算法·计算机视觉·c#
小明说Java10 小时前
常见排序算法的实现
数据结构·算法·排序算法
行云流水201911 小时前
编程竞赛算法选择:理解时间复杂度提升解题效率
算法
smj2302_7968265213 小时前
解决leetcode第3768题.固定长度子数组中的最小逆序对数目
python·算法·leetcode
cynicme13 小时前
力扣3531——统计被覆盖的建筑
算法·leetcode
core51213 小时前
深度解析DeepSeek-R1中GRPO强化学习算法
人工智能·算法·机器学习·deepseek·grpo
mit6.82414 小时前
计数if|
算法
a伊雪14 小时前
c++ 引用参数
c++·算法