滑动窗口在算法中的应用

滑动窗口是一种经典的算法技巧,就像在处理一系列动态数据时,用一扇可以滑动的“窗口”来捕捉一段连续的子数组或子字符串。通过不断地移动窗口的起点或终点,我们能够以较低的时间复杂度来解决一系列问题。在这篇文章中,我们将通过几个经典的 LeetCode 题目,使用 Java 语言来详细讲解滑动窗口的应用。


在这里插入图片描述

例题1:找到字符串中的所有异位词

题目背景
朋友小明在编程比赛中遇到了一个问题:如何在一个长字符串中找到所有与目标字符串异位的子串?我们需要通过滑动窗口找到所有这些位置。

题目描述
给定两个字符串 sp,找出 s 中所有 p 的异位词的起始索引。字符串仅包含小写字母,并且 ps 的长度都不超过 20,000。

示例

输入: s = "cbaebabacd", p = "abc"
输出: [0, 6]

代码实现

import java.util.*;

public class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> result = new ArrayList<>();
        if (s.length() < p.length()) return result;

        int[] pCount = new int[26];  // 记录字符串 p 中字符的频率
        int[] sCount = new int[26];  // 记录当前窗口中字符的频率

        for (char c : p.toCharArray()) {
            pCount[c - 'a']++;
        }

        int left = 0;
        for (int right = 0; right < s.length(); right++) {
            sCount[s.charAt(right) - 'a']++;
            
            // 如果窗口大小大于 p 的长度,收缩窗口
            if (right - left + 1 > p.length()) {
                sCount[s.charAt(left) - 'a']--;
                left++;
            }

            // 判断窗口内的字符频率与 p 是否一致
            if (Arrays.equals(sCount, pCount)) {
                result.add(left);
            }
        }
        
        return result;
    }
}

分析

  • 我们维护了两个频率表 pCountsCount,分别用于记录字符串 p 的字符频率和当前窗口的字符频率。
  • 时间复杂度为 O(n),其中 n 是字符串 s 的长度。

例题2:水果成篮

题目背景
我们去果园摘水果,朋友们想知道,如何在一个果树排列中,找到最长的连续子集,使得我们可以只用两个篮子装下这些水果。

题目描述
在一排树中,第 i 棵树上有 tree[i] 型号的水果。你可以选择两个篮子,每个篮子只能装一种型号的水果。你需要找到可以采摘的水果的最大数量。

示例

输入: tree = [1,2,1,2,1,3,3,4,3]
输出: 4

代码实现

import java.util.*;

public class Solution {
    public int totalFruit(int[] tree) {
        Map<Integer, Integer> basket = new HashMap<>();
        int left = 0, maxFruit = 0;

        for (int right = 0; right < tree.length; right++) {
            basket.put(tree[right], basket.getOrDefault(tree[right], 0) + 1);

            // 如果篮子里有超过两种水果,开始收缩窗口
            while (basket.size() > 2) {
                basket.put(tree[left], basket.get(tree[left]) - 1);
                if (basket.get(tree[left]) == 0) {
                    basket.remove(tree[left]);
                }
                left++;
            }

            // 记录当前窗口的最大长度
            maxFruit = Math.max(maxFruit, right - left + 1);
        }

        return maxFruit;
    }
}

分析

  • 这里我们使用 HashMap 来记录当前窗口中的水果种类和数量。
  • 当种类超过两个时,开始通过移动左指针缩小窗口,直到只剩下两种水果。
  • 时间复杂度为 O(n),空间复杂度为 O(1)。

例题3:最长重复字符替换

题目背景
小丽正在玩一个文字游戏,要求她通过最多 k 次字符替换,将字符串中的一段字符变成相同的字符。她希望找出其中能够获得最长重复字符子串的长度。

题目描述
给你一个仅由大写英文字母组成的字符串 s,你可以最多将 k 个字符替换为任意字符,求在执行上述操作后,能够得到的最长重复字符的子串的长度。

示例

输入: s = "AABABBA", k = 1
输出: 4

代码实现

public class Solution {
    public int characterReplacement(String s, int k) {
        int[] count = new int[26];  // 记录窗口内字符的频率
        int maxCount = 0, maxLen = 0, left = 0;

        for (int right = 0; right < s.length(); right++) {
            count[s.charAt(right) - 'A']++;
            maxCount = Math.max(maxCount, count[s.charAt(right) - 'A']);

            // 如果当前窗口大小减去窗口中最多的字符数大于 k,收缩窗口
            if (right - left + 1 - maxCount > k) {
                count[s.charAt(left) - 'A']--;
                left++;
            }

            maxLen = Math.max(maxLen, right - left + 1);
        }

        return maxLen;
    }
}

分析

  • 通过 count 数组记录每个字符的出现频率,并通过 maxCount 来维护窗口中出现最多的字符数。
  • 如果窗口的大小超过 k + maxCount,说明需要缩小窗口。
  • 时间复杂度为 O(n),因为我们只对每个字符遍历一次。

总结

滑动窗口在处理连续子数组或子字符串问题时展现了极大的灵活性。通过维护一个动态窗口,滑动窗口不仅能够帮助我们有效解决问题,还可以极大地优化时间复杂度。在这些例子中,我们用 Java 语言展示了滑动窗口在寻找异位词、最大水果采摘量、以及字符替换中的应用。滑动窗口算法的威力在于,它不仅高效,而且能够适应各种复杂的题目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/873563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

维信小程序禁止截屏/录屏

一、维信小程序禁止截屏/录屏 //录屏截屏,禁用wx.setVisualEffectOnCapture({visualEffect:hidden});wx.setVisualEffectOnCapture(Object object) 测试安卓手机&#xff1a; 用户截屏&#xff0c;被禁用 用户录屏&#xff0c;录制的是空白内容/黑色内容的视频。 二、微信小…

C++ | Leetcode C++题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> lexicalOrder(int n) {vector<int> ret(n);int number 1;for (int i 0; i < n; i) {ret[i] number;if (number * 10 < n) {number * 10;} else {while (number % 10 9 || numbe…

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求&#xff0c;要求做一款播放器&#xff0c;发现能力上跟EasyPlayer.js基本一致&#xff0c;满足要求&#xff1a; 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏&#xff08;单屏/全屏&#xff09; 多分屏&#xff08;2*2&#xff09; 多分屏…

【阿一网络安全】如何让你的密码更安全?(二) - 非对称加密

上次《【阿一网络安全】如何让你的密码更安全&#xff1f;(一) - 对称加密》提到加密算法的对称加密&#xff0c;我们这次来聊聊非对称加密。 和对称加密不同&#xff0c;非对称加密的加密密钥和解密密钥不同。 非对称加密 大概过程就是&#xff0c;发送方使用公钥对明文数据…

mac 安装redis

官网下载指定版本的redis https://redis.io/ 目前3.2.0 是最新最稳定的 版本 这里是历史版本下载 下载指定版本 安装 1.放到自定义目录下并解压 2.打开终端&#xff0c;执行命令 cd redis的安装目录下 make test -- 此命令的作用是将redis源代码编译成可执行文件&#xff0c…

SPI驱动学习五(如何编写SPI设备驱动程序)

目录 一、SPI驱动程序框架二、怎么编写SPI设备驱动程序1. 编写设备树2. 注册spi_driver3. 怎么发起SPI传输3.1 接口函数3.2 函数解析 三、示例1&#xff1a;编写SPI_DAC模块驱动程序1. 要做什么事情2. 硬件2.1 原理图2.2 连接 3. 编写设备树4. 编写驱动程序5. 编写app层操作程序…

C++语法知识点合集:11.模板

文章目录 一、非类型模板参数1.非类型模板参数的基本形式2.指针作为非类型模板参数3.引用作为非类型模板参数4.非类型模板参数的限制和陷阱&#xff1a;5.几个问题 二、模板的特化1.概念2.函数模板特化3.类模板特化(1)全特化(2)偏特化(3)类模板特化应用示例 三、模板分离编译1.…

微带结环行器仿真分析+HFSS工程文件

微带结环行器仿真分析HFSS工程文件 工程下载&#xff1a;微带结环行器仿真分析HFSS工程文件 我使用HFSS版本的是HFSS 2024 R2 参考书籍《微波铁氧体器件HFSS设计原理》和视频微带结环行器HFSS仿真 1、环形器简介 环行器是一个有单向传输特性的三端口器件&#xff0c;它表明…

使用Qt编程QtNetwork无法使用

使用 VS 构建 Qt 项目时 QtNetwork 无法使用的问题 - 摘叶飞镖 - 博客园 (cnblogs.com) 另外,强烈建议在使用QNetworkAccessManager之前看看这篇文章: Qt 之 QNetworkAccessManager踏坑记录-CSDN博客 C Qt开发&#xff1a;QNetworkAccessManager网络接口组件 阅读目录 1.1 …

在Ubuntu上运行QtCreator相关程序

背景&#xff1a;希望尝试在Linux系统上跑一下使用QtCreator相关的程序&#xff0c;因为有一些工作岗位要求有Linux上使用Qt的经验。 (1)我是把Windows上的程序移过来的&#xff0c;Windows上文件名称是不区分大小写的。 而Ubuntu上是区分的 所以一部分头文件需要进行修改&am…

idea创建SpringBoot项目

目录 1. 新建一个SpringBoot项目 2. 使用Springboot官网创建项目 3. 使用阿里云地址创建SpringBoot项目 4. 使用maven创建SpringBoot项目 5. 在Idea中隐藏指定文件/文件夹 1. 新建一个SpringBoot项目 Springboot2 要求jdk版本: 1.8 maven: 3.3 内嵌的tomcat: tomcat9 我们…

深度学习(一)-感知机+神经网络+激活函数

深度学习概述 深度学习的特点 优点 性能更好 不需要特征工程 在大数据样本下有更好的性能 能解决某些传统机器学习无法解决的问题 缺点 小数据样本下性能不如机器学习 模型复杂 可解释性弱 深度学习与传统机器学习相同点 深度学习、机器学习是同一问题不同的解决方法 …

11.5.软件系统分析与设计-面向对象的程序设计与实现

面向对象的程序设计与实现 设计模式 Java代码 C代码

SQL进阶技巧:每年在校人数统计 | 区间重叠问题

目录 0 问题分析 1 数据准备 2 问题分析 3 小结 区间重叠问题 0 问题分析 有一个录取学生人数表 in_school_stu,记录的是每年录取学生的人数及录取学生的学制,计算每年在校学生人数。 1 数据准备 create table in_school_stu as ( select stack(5,1,2001,2,1200,2,2000…

UML的图及其他图补充

一、UML图 1.类图 ‌类图‌是统一建模语言&#xff08;UML&#xff09;中的一种静态结构图&#xff0c;主要用于描述软件系统的静态结构。它显示了模型中的类、类的内部结构以及它们与其他类的关系。类图是面向对象建模的主要组成部分&#xff0c;用于对系统的词汇进行建模、对…

SigLIP——采用sigmoid损失的图文预训练方式

SigLIP——采用sigmoid损失的图文预训练方式 FesianXu 20240825 at Wechat Search Team 前言 CLIP中的infoNCE损失是一种对比性损失&#xff0c;在SigLIP这个工作中&#xff0c;作者提出采用非对比性的sigmoid损失&#xff0c;能够更高效地进行图文预训练&#xff0c;本文进行…

93. UE5 GAS RPG 应用负面效果表现

在上一篇文章里&#xff0c;我们实现了添加负面效果GE&#xff0c;并且在添加GE时&#xff0c;也会给角色应用一个负面效果标签作为标识。在这一篇里&#xff0c;我们将通过负面效果标签标识&#xff0c;应用角色身上展现对应的负面效果的表现。 我们将在这篇文章里添加一个自定…

【c++进阶[五]】list相关接口介绍及list和vector的对比

&#x1f493;博主CSDN主页::Am心若依旧&#x1f493; ⏩专栏分类c从入门到精通⏪ &#x1f69a;代码仓库:青酒余成&#x1f69a; &#x1f339;关注我&#x1faf5;带你学习更多c   &#x1f51d;&#x1f51d; 1.前言 本章重点 本章重点讲解list的接口函数的熟悉&#xf…

Linux-RPM与YUM

目录 前言&#xff1a; rpm包的管理 rpm包的简单查询指令 ​编辑 rpm包名的基本格式 rpm包名基本格式 ​编辑 卸载rpm包 细节问题 安装rpm包 yum yum的基本指令 安装指定的yum包 yum报错 问题描述&#xff1a; 解决方法&#xff1a; 前言&#xff1a; Linux操…

电脑硬盘数据丢失了怎么恢复?简单实用的硬盘数据找回的方法

我们的电脑使用硬盘作为存储设备来保存数据&#xff0c;硬盘里的数据是存储在扇区上&#xff0c;这些存储数据的单元则位于表面有磁性材料的旋转的盘片上。硬盘内部的磁头悬浮于高速旋转的盘片上&#xff0c;用于读写和检索数据。 假如我们使用电脑时不小心删除了某个文件&…