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

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

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

题目描述:

给定一个字符串 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),仅用常数级额外变量。
相关推荐
江畔柳前堤5 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore6 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考8 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX9 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面9 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号9 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽10 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI10 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者11 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者11 小时前
【征程6】校准量化中HistogramObserver解析
算法