滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C++

news2024/10/11 7:34:04

滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C++

  • 1. 题目解析
  • 2. 算法分析
  • 3. 代码实现
  • 4. 举一反三:串联所有单词的子串


1. 题目解析


leetcode链接:https://leetcode.cn/problems/VabMRr/

给定两个字符串 sp,找到 s 中所有 p变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

变位词 指字母相同,但排列不同的字符串。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的变位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的变位词。

示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的变位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的变位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的变位词。

2. 算法分析


1. 暴力解法

  • 首先能判断子串是否是变位词,这可以通过哈希表实现,因为只要是变位词,他们每个字母的数量都是一样的。(以示例1为例)

在这里插入图片描述

  • leftright的初始位置如图,之后不断将right右移,并且将right指向的元素加入哈希表(记为hash)。
  • right走到e时,发现e不在字符串p形成的哈希表中(记为hash_p),需要返回,直接让right返回,left++即可。同时right - left = p.size(),构成了一个变位词。

在这里插入图片描述

  • 另一种需要返回right的情况是,当left指向第二个b,right指向第三个b时,此时将right指向的元素加入hash,发现hash中该元素的数量大于hash_p中该元素的数量,此时也是需要返回的。

在这里插入图片描述

2. 滑动窗口

  • 在暴力解法的基础上,优化right的返回:
    • 当出现right指向的元素不在hash_p的情况时,直接让left移动到right的位置即可,同时清空hash
    • 当出现right指向的元素在hash中的数量,超过hash_p时,不需要移动right,只需要让left不断++,然后更改hash中的元素数量,直到hash中该元素的数量不再大于hasp_p即可。

3. 代码实现


1. 暴力解法

  • 会超时。
class Solution {
public:
    vector<int> findAnagrams(string s, string p) 
    {
        vector<int> ret;
        int n = s.size();
        int m = p.size();
        unordered_map<char, int> hash_p;    // 由字符串p形成的哈希表
        unordered_map<char, int> hash;

        for (auto e : p)
            hash_p[e]++;

        for (int left = 0, right = 0; right <= n; right++)
        {
            if (right == n) // 处理边界情况
            {
                if (right - left == m) 
                   ret.push_back(left);
                break;
            }
             
            hash[s[right]]++;
            if (!hash_p.count(s[right]) || hash[s[right]] > hash_p[s[right]])
            {
                if (right != n && right - left == m) ret.push_back(left);
                right = left;
                left++;
                hash.clear();
            }
        }
        
        return ret;
    }
};

2. map版

class Solution {
public:
    vector<int> findAnagrams(string s, string p) 
    {
        vector<int> ret;
        int n = s.size();
        int m = p.size();
        unordered_map<char, int> hash_p;    // 由字符串p形成的哈希表
        unordered_map<char, int> hash;

        for (auto e : p)
            hash_p[e]++;

        for (int left = 0, right = 0; right <= n; right++)
        {    
            // 处理边界情况
            if (right == n)
            {
                if (right - left == m) 
                {
                    ret.push_back(left);
                }
                break;
            }
            
            hash[s[right]]++;   // 进窗口
            if (!hash_p.count(s[right]) || hash[s[right]] > hash_p[s[right]])
            {
                if (right != n && right - left == m) ret.push_back(left); // 更新结果
                // 出窗口
                if (!hash_p.count(s[right]))
                {
                    left = right + 1;
                    hash.clear();
                }
                else if (hash[s[right]] > hash_p[s[right]])
                {
                    while (hash[s[right]] > hash_p[s[right]])
                    {
                        hash[s[left]]--;
                        left++;
                        if (hash[s[left]] == 0)
                            hash.erase(s[left]);
                    }
                }
            }
        }
        
        return ret;
    }
};

3. 数组模拟哈希(最快)

class Solution {
public:
    vector<int> findAnagrams(string s, string p) 
    {
        vector<int> ret;
        int n = s.size();
        int m = p.size();
        int hash_p[26] = {0};
        int hash[26] = {0};

        for (auto e : p)
            hash_p[e - 'a']++;

        for (int left = 0, right = 0; right <= n; right++)
        {    
            // 处理边界情况
            if (right == n)
            {
                if (right - left == m) 
                {
                    ret.push_back(left);
                }
                break;
            }

            hash[s[right] - 'a']+=1;   // 进窗口
            if (!hash_p[s[right] - 'a'] || hash[s[right] - 'a'] > hash_p[s[right] - 'a'])
            {
                if (right != n && right - left == m) ret.push_back(left); // 更新结果
                // 出窗口
                if (!hash_p[s[right] - 'a'])
                {
                    left = right + 1;
                    for (int i = 0; i < 26; i++) hash[i] = 0;
                }
                else if (hash[s[right] - 'a'] > hash_p[s[right] - 'a'])
                {
                    while (hash[s[right] - 'a'] > hash_p[s[right] - 'a'])
                    {
                        hash[s[left] - 'a']--;
                        left++;
                    }
                }
            }
        }
        
        return ret;
    }
};

4. 举一反三:串联所有单词的子串


leetcode链接:https://leetcode.cn/problems/substring-with-concatenation-of-all-words/description/

class Solution {
public:
    string getStr(string s, int pos, int size)
    {
        string tmp;
        for (int i = 0; i < size; i++)
        {
            tmp += s[pos++];
        }
        return tmp;
    }

    vector<int> findSubstring(string s, vector<string>& words) 
    {
        vector<int> ret;
        int n = s.size(), m = words.size(), size = words[0].size();

        unordered_map<string, int> hash_w;
        unordered_map<string, int> hash;

        for (auto e : words)
            hash_w[e]++;

        // 一共滑动size次
        for (int i = 0; i < size; i++)
        {
            hash.clear();   // 细节
            for (int left = i, right = i; ; right += size)
            {
                // 边界情况
                if (right + size > n)
                {
                    if ((right - left) / size == m && (right - left) % size == 0)
                        ret.push_back(left);    // 更新结果
                    break;
                }

                string tmp = getStr(s, right, size);
                hash[tmp]++;     // 进窗口
                if (!hash_w.count(tmp) || hash[tmp] > hash_w[tmp])
                {
                    if (right != n && (right - left) / size == m && (right - left) % size == 0)
                        ret.push_back(left);    // 更新结果
                
                    // 出窗口
                    if (!hash_w.count(tmp))
                    {
                        left = right + size;
                        hash.clear();
                    }
                    else if (hash[tmp] > hash_w[tmp])
                    {
                        while (hash[tmp] > hash_w[tmp])
                        {
                            string tmp2 = getStr(s, left, size); // 细节
                            hash[tmp2]--;
                            left += size;
                            if (hash.count(tmp2) == 0)
                                hash.erase(tmp2);
                        }
                    }
                }
            }
        }

        return ret;
    }
};

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

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

相关文章

helm 测试安装redis

helm search repo redis # 搜索redis的chart helm show readme bitnami/redis # 展示安装相关文档&#xff08;readme文件&#xff09; 拉取指定版本的安装包&#xff08;chart&#xff09; helm pull bitnami/redis --version 17.4.3 解压安装包 tar -xf redis-17.4.3.tgz …

Vue3 动态路由实现的一种方法

动态路由 目的&#xff1a; 根据服务器传回来的数据动态的注册路由信息&#xff0c;登录用户的角色不同生成的菜单不同 使用插件做动态路由的好处&#xff1a; 路由页面增加或者减少时&#xff0c;只需要增加或减少相关的路由文件&#xff0c;不需要再修改代码 服务器返回的信…

POI数据的处理与分析

POI概念 POI&#xff08;Point of Interest&#xff0c;兴趣点&#xff09;数据指的是地理空间数据中的一类&#xff0c;表示某一具体地点或位置的信息。通常&#xff0c;这些数据包含位置坐标&#xff08;经纬度&#xff09;、名称、地址、类别和其他相关信息。POI 数据广泛应…

毕业设计 深度学习水果识别

文章目录 1 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果 1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果…

算法剖析:双指针

文章目录 双指针算法一、 移动零1. 题目2. 算法思想3. 代码实现 二、 复写零1. 题目2. 算法思想3. 代码实现 三、 快乐数1. 题目2. 算法思想3. 代码实现 四、 盛水最多的容器1. 题目2. 算法思想3. 代码实现 五、有效三角形的个数1. 题目2. 算法思想3. 代码实现 六、 和为 s 的两…

【EXCEL数据处理】000020 案例 保姆级教程,附多个操作案例。EXCEL使用表格。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000020 案例 保姆级教程&#xff0c;附多个操作案例。…

【强训笔记】day27

NO.1 代码实现&#xff1a; #include<iostream>using namespace std;int n,m; int main() {cin>>n>>m;long long retn;for(int i0;i<m-1;i)retret*(n-1)%109;cout<<ret<<endl;return 0; }NO.2 思路&#xff1a;bfs遍历实现&#xff0c;dis…

Android架构--MVVM

一、开发架构 是什么&#xff1f; 二、Android开发中的架构 具体到Android开发中&#xff0c;开发架构就是描述 视图层、逻辑层、数据层 三者之间的关系和实施&#xff1a; 视图层&#xff1a;用户界面&#xff0c;即界面的展示、以及交互事件的响应。 逻辑层&#xff1a;为…

IL2CPP和Mono的区别

Mono 是一种开源的跨平台 .NET 框架实现&#xff0c;能够执行 C# 代码。Unity 使用 Mono 来处理 C# 脚本&#xff0c;并通过 JIT&#xff08;Just-In-Time&#xff09;即时编译器将托管代码转换为本地机器代码&#xff0c;随后在目标平台上执行 IL2CPP 代表 Intermediate Lang…

《业务三板斧:定目标、抓过程、拿结果》读书笔记3

关于目标&#xff0c;关键是共识目标&#xff1a; 为什么不是共识目标&#xff0c;而是共信目标&#xff1f; 共识目标是指管理者通过沟通&#xff0c;让所有团队成员就目标以及实现目 标的方法达成一致。当个人与组织、个人与个人之间出现“路径选择 差异”的时候&#xff0c;…

算法专题四: 前缀和

目录 1. 前缀和2. 二维前缀和3. 寻找数组的中心下标4. 除自身以外数组的乘积5. 和为k的子数组6. 和可被K整除的子数组7. 连续数组8. 矩阵区域和 博客主页:酷酷学!!! 感谢关注~ 1. 前缀和 算法思路: 根据题意, 创建一个前缀和数组, dp[i] dp[i -1] arr[i], 再使用前缀和数组,…

Go编译为可执行文件

在window下打包成其他系统可运行的文件 1.在window下打包成window下可执行文件 在项目main.go同级目录下&#xff0c;逐条执行以下命令 set CGO_ENABLED0 set GOOSwindows set GOARCHamd64 go build -o main-windows.exe main.go 2.在window下打包成linux 在项目main.go同级目…

Android Codec2 CCodec(十六)C2AllocatorGralloc

这一篇文章我们一起来瞧瞧2D&#xff08;Graphic&#xff09; buffer分配器C2AllocatorGralloc是如何工作的。 1、GraphicBuffer 在Android系统中&#xff0c;GraphicBufferAllocator和GraphicBufferMapper是与图形缓冲区&#xff08;Graphic Buffers&#xff09;管理相关的重…

Python爬取b站视频:验证cookie是否有效

具体代码 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0,Referer: https://www.bilibili.com/,Origin: https://www.bilibili.com } def readCooki…

Nginx02-安装

零、文章目录 Nginx02-安装 1、Nginx官网 Nginx官网地址&#xff1a;http://nginx.org/ 2、Nginx下载 &#xff08;1&#xff09;Nginx下载 下载页地址&#xff1a;http://nginx.org/en/download.html &#xff08;2&#xff09;更老版本下载 下载页地址&#xff1a;http…

四、链表————相关算法探讨(持续更新中)

链表中相关算法探讨 前言一、移除链表元素1.1 思路分析1.2 解法探讨1.2.1 直接删除1.2.2 创建虚拟头节点来删除1.2.3 递归版删除 二、反转列表2.1 思路分析2.2 做法2.2.1 创建新链表方式2.2.2 双指针法2.2.3 递归法 三、两两交换链表中的节点3.1 思路分析3.2 解法探讨3.2.1 不使…

重磅 | 清华大学刘知远老师领衔的大模型公开课2024年第二季来了!助教阵容强大,零基础大模型从入门到精通,看这个就够了!

本文由readlecture.cn转录总结。ReadLecture专注于音、视频转录与总结&#xff0c;2小时视频&#xff0c;5分钟阅读&#xff0c;加速内容学习与传播。 更多讲座、采访干货内容&#xff0c;欢迎关注公众号“ReadLecture”获取&#xff01;公众号后台直接回复&#xff0c;可与公众…

RK3568笔记六十四:SG90驱动测试

若该文为原创文章,转载请注明原文出处。 前面有测试过PWM驱动,现在使用两种方式来产生PWM驱动SG90,实现舵机旋转任意角度 方法一:使用硬件PWM 方法二:使用高精度定时器,GPIO模拟PWM. 一、PWM子系统框架 二、SG90控制方法 舵机的控制需要MCU产生一个周期为20ms的脉冲信号…

python实现DES算法

DES算法 一、算法介绍1.1 背景1.2 原理1.3 基本功能函数1.3.1 初始置换函数 I P IP IP1.3.2 f f f 轮函数1.3.3 逆初始置换函数 I P − 1 IP^{-1} IP−1 1.4 子密钥的生成 二、代码实现2.1 子密钥生成实现2.2 DES加解密实现2.3 完整代码 三、演示效果 一、算法介绍 1.1 背景…

SpringBoot框架在旅游管理中的应用与实践

第三章 系统分析 3.1可行性分析 对所有的系统来说&#xff0c;都有可能会受到时间和空间上的制约。所以&#xff0c;我们在设计每一个项目的时候&#xff0c;必须对该系统实行可行性分析&#xff0c;这样不但能够降低项目的危害&#xff0c;还能改降低人力、物力和财力的损耗。…