滑动窗口思想练习题

news2024/9/23 10:26:22

文章目录

  • 1. 找到字符串中所有字母异位词
    • 做法一:采用两个数组分别记录字符出现频次
    • 做法二:采用diff记录s和p字符串中字符的频次差
  • 2. 串联所有单词的子串
  • 个人理解,如有异议,欢迎指正!

1. 找到字符串中所有字母异位词

题目链接
两种做法统一思想:

  1. 字母异位词:只要两个字符串中的字母出现频次是相同的,就代表是字母异位词。
  2. 为了区分是s中独有的,还是p中独有的,s中的在记录频次时++,p中的记录时–,数组中±抵消为0时代表着这个字符是都有的,也就是满足情况的。
  3. s记录频次的次数是以p的长度,也就是p的记录频次次数一致。

做法一:采用两个数组分别记录字符出现频次

如果两个数组中字符映射的频次相同的话,代表着是字母异位词。

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int slen=s.size();
        int plen=p.size();
        if(slen<plen)
            return vector<int>();
        vector<int>ans;
        vector<int>sCount(26);
        vector<int>pCount(26);
        //分别记录频次,只不过要以p的长度为准
        for(int i=0;i<plen;i++)
        {
            ++sCount[s[i]-'a'];
            ++pCount[p[i]-'a'];
        }
        if(sCount==pCount)
        {
            ans.emplace_back(0);
        }
        for(int i=0;i<slen-plen;i++)
        {
            --sCount[s[i]-'a'];//滑动窗口左边界右移一个,自然要将去掉的那一个的字母频次--
            ++sCount[s[i+plen]-'a'];//滑动窗口右边界右移一个,自然要将新添加的那一个的字母频次++
            if(sCount==pCount)
                ans.emplace_back(i+1);
        }
        return ans;
    }
};

做法二:采用diff记录s和p字符串中字符的频次差

我们不用两个数组映射,只需要一个,并且添加diff记录±抵消情况。如果抵消结果是0,就代表是字母异位词。
经历窗口移动之后由不同词频变成相同词频,也就是代码中的从1->0,-1->0的过程,都需要将diff–,表示词频差的缩小。

class Solution {
public:
vector<int> findAnagrams(string s, string p) 
{
    int slen=s.size();
    int plen=p.size();
    if(slen<plen)
        return vector<int>();
    vector<int>count(26);
    vector<int>ans;
    for(int i=0;i<plen;i++)
    {
        count[s[i]-'a']++;
        count[p[i]-'a']--;
    }
    //记录diff就是二者词频差
    int diff=0;
    for(int i=0;i<26;i++)
    {
        if(count[i]!=0)
            diff++;
    }
    //全都满足
    if(diff==0)
    ans.emplace_back(0);
    //注意边界
    for(int i=0;i<slen-plen;i++)
    {
        if(count[s[i]-'a']==1)//=1,代表只属于s,和p不同,经历左窗口右移一位,字符就变成相同词频,diff要--。该字母计数--也可理解为图2
            diff--;
        else if(count[s[i]-'a']==0)//下图1中的c字符,属于新来的,要添加他的映射,自然词频又++
            diff++;
        --count[s[i]-'a'];//左边界字符取出,自然他的计数--

        if(count[s[i+plen]-'a']==-1)
            diff--;
        else if(count[s[i+plen]-'a']==0)
            diff++;
        ++count[s[i+plen]-'a'];
        if(diff==0)
            ans.emplace_back(i+1);
    }
    return ans;
}
};
  • 图一:这是记录之后count数组总情况
    在这里插入图片描述- 图二:帮助理解
    在这里插入图片描述

2. 串联所有单词的子串

题目链接

有了上面第二种做法的思想经验,同样记录词频差,然后将上面的单一字符升级为字符串,数据结构上从count(26)升级为哈希映射的unordered_map<string,int>ht的数据结构,并且采用字符串是否在ht的形式记录上题的词频差。

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        int slen=s.size();
        int m=words.size();
        int n=words[0].size();
        vector<int>ans;

        for(int i=0;i<n&&i+m*n<=slen;i++)
        {
            unordered_map<string,int>ht;
            for(int j=0;j<m;j++)//一组几个单词
            {
                ht[s.substr(i+j*n,n)]++;
            }
            for(string &word:words)
            {
                if(--ht[word]==0)
                    ht.erase(word);
            }

            for(int start =i;start<slen-m*n+1;start+=n)
            {
                //判断分组中的右半部分词频是否相同
                if(start!=i)
                {
                    //如果是m=3,结出来的就是一组中的第三个单词
                    string word=s.substr(start+(m-1)*n,n);
                    //滑动窗口右部分,原来是-1,++先之后为0
                    //原来不同现在相同
                    if(++ht[word]==0)//为什么原来是-1就代表右边界呢?因为同上面题第二个解法ht建立映射,遍历s的时候是从左向右截p.size个,规定s中的++,p中的--,所以1的存在就在左边,-1的存在就在右边
                        ht.erase(word);//同理,ht建立映射引用时,虽然不存在左右的绝对区分(HASHFUNC决定),但是1和-1就代表着左边界还是右边界。

                    //如果是m=3,结出来的就是一组中的第2个单词
                    word=s.substr(start-n,n);
                    //滑动窗口右部分,原来是1,先--之后为0
                    //原来不同现在相同
                    if(--ht[word]==0)
                        ht.erase(word);
                }

                //p题刚开始的中diff==0,第一个字符开始就可以
                //本题中,第一个切割的就可以
                //判断分组中的左半部分词频是否相同
                if(ht.empty())
                    ans.emplace_back(start);
            }
        }
        return ans;
    }
};
  • 举例帮助理解图:
    在这里插入图片描述

个人理解,如有异议,欢迎指正!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XiaoMi手机MIX 2S线刷固件和刷入Recovery

mix 2s 固件下载地址 https://web.vip.miui.com/page/info/mio/mio/detail?postId4865868&app_versiondev.20051 miflash线刷工具下载地址 https://miuiver.com/miflash/ 安装miflash线刷工具 点击安装驱动 打开miflash 手机关机按音量下加开机键进入bootloader&#xf…

Spring boot整合rocketmq(windows)

目录 1.环境搭建 2.命名服务器和业务服务器的启动 3.名词说明 4.执行步骤 5.示例 1.导入依赖 2.配置(至少指定下面两个) 3.代码 6.常见问题 1.环境搭建 下载地址&#xff1a;https://rocketmq.apache.org/解压缩进行安装&#xff0c;默认服务端口&#xff1a;9876 环…

执行 select ... for update 语句,如果查询条件没有索引字段的话,是加行锁还是加表锁?

大家好&#xff0c;我是小林。 昨天在群里看到大家在讨论一个 MySQL 锁的问题&#xff0c;就是执行 select … for update 语句&#xff0c;如果查询条件没有索引字段的话&#xff0c;是加「行锁」还是加「表锁」&#xff1f; 如果你做过这个实验的话&#xff0c;你会发现执行…

数据结构刷题训练营1

开启蓝桥杯备战计划&#xff0c;每日练习算法一题&#xff01;&#xff01;坚持下去&#xff0c;想必下一年的蓝桥杯将会有你&#xff01;&#xff01; 笔者是在力扣上面进行的刷题&#xff01;&#xff01;由于是第一次刷题&#xff01;找到的题目也不咋样&#xff01;所以&a…

SPRING-了解3-注解

IOC容器操作Bean 注解格式&#xff1a;注解名称(属性名称属性值,属性名称属性值) 放在类&#xff0c;方法&#xff0c;属性都可以 目的&#xff1a;简化XML配置 对象创建四大注解 1&#xff09;用的位置不是强制的 Component 最普通 Service 用在service层 Controlle…

接口测试(十)—— telnet和python代码测试dubbo接口

目录 一、传智健康项目介绍 1、项目描述 2、目标用户群体 3、项目模块 4、系统框架 二、Dubbo接口测试 1、RPC 2、Dubbo 3、查阅API文档 三、Telnet工具远程调用 1、启用telnet 2、telnet远程连接服务 3、telnet调用服务接口 四、python借助dubbo远程调用 1、安…

MySQL~JDBC

10、JDBC&#xff08;重点&#xff09; 10.1、数据库驱动 驱动&#xff1a;声卡、显卡、数据库 我们的程序会通过 数据库 驱动&#xff0c;和数据库打交道&#xff01; 10.2、JDBC SUN公司为了简化 开发人员的&#xff08;对数据库的统一&#xff09;操作&#xff0c;提供了…

剑指offer常见题 - 链表问题(一)

二叉树相关算法 链表相关知识点&#xff1a; 链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 知识点一&#xff1a;链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;…

IDEA中如何使用Vim?看完本教程,让你用IDEA用到爽~(建议收藏)

目录 前言 Vim有什么特点&#xff1f; 为什么我要安利你在 IEAD 中使用Vim? Vim 一、环境配置 二、Vim的使用 2.1、方向键 hjkl 2.2、​编辑复制&粘贴 2.3、选择代码块并删除 2.4、块级删除 2.5、各种插入模式 2.5.1、以下是gif演示 2.6、jump&#xff08;解放鼠…

毕业设计 stm32智能电子秤系统 - 物联网 嵌入式 单片机

文章目录0 前言1 简介2 主要器件3 实现效果4 设计原理4.1 STM32F103C8T64.2 HX711压力传感器5 部分核心代码6 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&…

【OpenCV】Ubuntu配置OpenCV环境

1.从官网下载opencv包拷贝到虚拟机Ubuntu中&#xff0c; 虚拟机与主机传输文件可以采用 vmware tool、共享文件夹或者远程连接工具 2.解压得到对应版本号文件夹&#xff0c;我的是opencv-3.4.2 3.修改文件权限chmod -R 777 opencv-3.4.2 从win10进入Ubuntu中的文件压缩包解…

2022年云南省—信息安全管理与评估赛项竞赛规程

2022年云南省职业院校技能大赛 信息安全管理与评估赛项竞赛规程 一、赛项名称 赛项编号&#xff1a;No.11 赛项名称&#xff1a;信息安全管理与评估 英语翻译&#xff1a;Information Security Management and Evaluation 赛项组别&#xff1a;高职组 赛项归属产业&a…

本周大新闻|John Carmack从Meta离职,OPPO发布双目AR一体机仅38g

本周大新闻&#xff0c;AR方面&#xff0c;微软已向客户承诺新款HoloLens&#xff1b;NASA成立Joint AR项目&#xff0c;计划在宇航服头盔中加入AR功能&#xff1b;OPPO Air Glass 2发布&#xff0c;双目光波导仅38g&#xff1b;Rokid开设全球首家品牌旗舰店&#xff1b;谷歌为…

【数据结构】二叉树的节点总个数、叶子节点个数、第K层节点个数、二叉树的深度

目录 1.结点总个数 1.1 局部静态变量法 思维 代码 不足之处 2.传指针法 程序代码 3.递归法 思想 程序代码 详细过程 2.叶子节点个数 思想 程序代码 3.第K层节点个数 思想 程序代码 4.二叉树深度 思想 程序代码 求二叉树节点总个数、叶子节点个数、第k层节点…

汀丶的创作纪念日

机缘 csdn的博龄5年了&#xff0c;但实际创作时间只有两年&#xff1b;第一次接触csdn主要是用来查找代码bug并收藏一些有价值博客&#xff0c;但渐渐地自己也就习惯把自己学到的知识和技术分享出来&#xff0c;一起共建。 主要是关于机器学习、强化学习、数据挖掘、强化学习以…

ADI Blackfin DSP处理器-BF533的开发详解62:DSP控制ADXL345三轴加速度传感器-贪食蛇游戏(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 MEMS三轴加速度传感器 我做了一个三轴加速度传感器的子卡&#xff0c;插在这个板子上&#xff0c;然后写了一些有意思的应用程序。 代码实现功能…

Bootstrap5 侧边栏导航(Offcanvas)

Bootstrap5 侧边栏侧边栏类似于模态框&#xff0c;在移动端设备中比较常用。 创建滑动导航 我们可以通过 JavaScript 来设置是否在 .offcanvas 类后面添加 .show 类&#xff0c;从而控制侧边栏的显示与隐藏&#xff1a; .offcanvas 隐藏内容 (默认).offcanvas.show 显示内容…

JVM之native关键字与PC寄存器

native关键字&#xff1a; native关键字主要用于修饰方法&#xff1a; 被native关键字修饰的方法叫做本地方法&#xff0c;一个native方法就是一个Java调用非Java代码的接口&#xff0c;该方法的实现由非Java语言实现&#xff0c;而是使用C或C等其他编程语言实现 native方法…

Compose 和 Android 传统View 互相调用

1. 前言 Compose 具有超强的兼容性&#xff0c;兼容现有的所有代码&#xff0c;Compose 能够与现有 View 体系并存&#xff0c;可实现渐进式替换。这就很有意义了&#xff0c;我们可以在现有项目中一小块一小块逐步地替换Compose&#xff0c;或者在旧项目中实现新的需求的时候…

设计模式之外观模式

Facade design pattern 外观模式的概念、外观模式的结构、外观模式的优缺点、外观模式的使用场景、外观模式的实现示例、外观模式的源码分析 1、外观模式的概念 外观模式&#xff0c;为多个复杂的子系统提供一个统一的接口&#xff0c;使得这些子系统更加容易被访问。在现有的…