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

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

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

题目描述:

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

示例:

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

解题思路:

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

  1. 定义窗口左右指针 left、right,哈希数组 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. 定义窗口左右指针 left、right,变量 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,最多可以翻转 k 个 0,返回操作后数组中连续 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])

解题思路:

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

  1. 定义窗口左右指针 left、right,变量 zeros 统计窗口内 0 的个数。
  2. 右指针 right 遍历数组,遇到 0 则 zeros++。
  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 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
罗西的思考5 小时前
【轻量化复刻大模型 / KIMI K3】KDA 模块交互式演示
人工智能·算法·机器学习
nm_zfyjt7 小时前
信息流广告投放优化实践:线索成本评估模型与转化链路重构(家装建材案例)
算法·重构·内蒙古朋友圈广告服务商·内蒙古朋友圈获客
w_zero_one8 小时前
算法--构造
java·数据结构·算法
其实防守也摸鱼9 小时前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
小超人诞生日记10 小时前
C++ 智能指针的使用及其原理详解
c++·算法
AiNightVision13 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
牧羊人.33314 小时前
卷积神经网络之VGG
人工智能·深度学习·神经网络·算法·cnn
小郎君65815 小时前
Vue 多标签页的加载态设计:为什么我没有用 Suspense 实现 PageLoading
vue.js·算法