算法Day09 | KMP,28. 实现 strStr() ,459.重复的子字符串

news2024/9/21 1:44:52

Day09

    • KMP
    • 28. 实现 strStr()
    • 459.重复的子字符串

KMP

KMP是三个人人名缩写,用于在文本字符串text中搜索pattern字符串,返回在text中第一出现的位置。
算法做法就是在暴力匹配的基础上加速匹配。通过对pattern字符串求next数组(该数组也成为前缀表),来跳过text部分匹配。next数组是为了实现跳过部分字符串的功能来设计的。暴力匹配的时间复杂度为 O ( m × n ) O(m\times n) O(m×n),KMP的时间复杂度为 O ( m + n ) O(m + n) O(m+n)

如何求出next数组?通过求出pattern所有字符子串的最长相等前、后缀构成next数组。具体实现可能存在其他加工,如对next数组减一,位移一位等。


假设有abbabbk,对于字符k有一个信息,k之前字符串中,前、后缀匹配最大长度为3。其中前、后缀为k前字符串的子字符串,即不包含整体abbabb字符串。为什么不包含,因为是next数组对应长度的下标不能等于它本身,k是第6个元素,next[k] != 6,而且整体字符串也一定相等,无意义。

int next[] = {-1/*人为规定*/, 0/*根据定义*/, 0/1, ...};

求next数组是往前跳的过程,最后用到前三个元素来得到最终数组。

d4779b1360e9149fe4265c7afc4f631
0b8fd333c19d3f228d872827b21f74c
b7ef04f09a89f04411565a5cbf1b608
0e1a3cf49c881dba57b070df93deaff

010f77584f1ff064d7ac05c0b700a6e

//通过回跳得到完整的next数组
void getNext(const string& s, int* next) {
    //初始化next数组
    next[0] = -1;
	//由于next数组是看之前的字符。当s只有一个长度时,之前没有字符。所以只能是在此跳出。
	if (s.size() == 1) return;
    next[1] = 0;

    int i = 2;//遍历next数组,next数组的下标
    int cn = 0;//回跳的值,也是next数组的值
    while (i < s.size()) {
        if (s[i - 1] == s[cn]) {//next[i]是用next[i-1]求
            next[i++] = ++cn;//i为cn+1
        } else if (cn > 0) {//cn还可以往前跳
            cn = next[cn];
        } else {
            next[i++] = 0;//next[i]为0
        }
    }
}
int KMP(const string& text, const string& pattern) {
    int next[pattern.size()];
    getNext(pattern, next);
    int i = 0/*遍历text*/, j = 0/*遍历pattern*/;

    //保持i的位置不变,通过调节j的位置来匹配字符,直到i匹配完毕,匹配i+1
    while (i < text.size() && j < pattern.size()) {
        if (text[i] == pattern[j]) {//匹配上了,对比下一个
            i++;
            j++;
        } else if (j != 0) {//j还可以往回跳
            j = next[j];
        } else {//j跳不动了。i匹配不上,匹配i+1
            i++;
        }
    }
    //是否是根据j跳出的边界
    //j跳出while表示已经配出相同的了,才会导致j++到出界
    //不是因为j跳出的while,说明没有找到
    return j == pattern.size() ? i - j : -1;//i-j对应找到的下标
}

对第六行代码 if (s.size() == 1) return;,没有这一句,当字符串s只有一个字符时,next数组应该直接返回next[1] = {-1},如果不跳出,则返回next[2] = {-1, 0};所以会造成dynamic-stack-buffer-overflow
本地编译器来说,不加这一句也能通过,应该是给优化掉了。
LeetCode没有优化掉,不过还是应该填上这一句,保证代码的稳定。


28. 实现 strStr()

题目链接:28. 实现 strStr()
KMP代码同上

class Solution {
public:
    void getNext(const string &s, int* next) {
        next[0] = -1;
        if (s.size() == 1) return;
        next[1] = 0;
        int i = 2;
        int cn = 0;
        while (i < s.size()) {
            if (s[i - 1] == s[cn]) {
                next[i++] = ++cn;
            } else if (cn > 0) {
                cn = next[cn];
            } else {
                next[i++] = 0;
            }
        }
    }
    int strStr(string haystack, string needle) {
        int next[needle.size()];
        getNext(needle, next);
        int i = 0;
        int j = 0;
        while (i < haystack.size() && j < needle.size()) {
            if (haystack[i] == needle[j]) {
                i++;
                j++;
            } else if (j > 0) {
                j = next[j];
            } else {
                i++;
            }
        }
        return j == needle.size() ? i - j : -1;
    }
};

459.重复的子字符串

题目链接: 459.重复的子字符串
移动匹配
字符串s中有重复,s+s也会包含serase()时间复杂度为 O ( n ) O(n) O(n)

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string ss = s + s;
        ss.erase(ss.begin());
        ss.erase(ss.end() - 1);
        return ss.find(s) != string::npos ? true : false;
    }
};

KMP
用到了next数组,根据next数组的构成原则可得,重复的子字符串 = 字符串 - 最长相等前后缀。如果没有最长相等前后缀,直接返回false

class Solution {
public:
    void getNext(const string& s, int* next) {
        next[0] = -1;
        if (s.size() == 1) return;
        next[1] = 0;
        int i = 2;
        int cn = 0;
        while (i < s.size()) {
            if (s[i - 1] == s[cn]) {
                next[i++] = ++cn;
            } else if (cn > 0) {
                cn = next[cn];
            } else {
                next[i++] = 0;
            }
        }
    }
    bool repeatedSubstringPattern(string s) {
        int len = s.size();
        
        int next[len + 1];//多一位是因为next数组的构造不同,需要整个字符串的next数组
        
        getNext(s + 'A'/*只要加一个不满足s要求的字符都行*/, next);
        //比如字符串是"aba",变成"abaA"
        
        return (next[len] != 0/*等于0,直接跳出为false*/ && len % (len - next[len]) == 0) ? 
                true : false;
    }
};

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

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

相关文章

element ui 表格内嵌图片预览展示样式问题 (element plus)

❤️砥砺前行&#xff0c;不负余光&#xff0c;永远在路上❤️ 目录 前言一、问题二、解决 前言 一、问题 二、解决 添加上preview-teleported 属性即可。

ChatGPT ✖️ 前端 = 有点er意思

HOT! HOT! HOT! &#x1f525; &#x1f525; &#x1f525; ChatGPT登上了国内各大平台的热搜榜&#xff0c;应该在去年11月末的时候就有不少同学了解并使用过&#xff0c;那个时候它刚刚问世&#xff0c;在互联网圈子里有了很大的热度&#xff0c;但是对于大众来说&#xff…

OpenGLES读写图像数据(内存与GPU)——使用PBO

一、什么是PBO 在 OpenGL 开发中&#xff0c;特别是在低端平台上处理高分辨率的图像时&#xff0c;图像数据在内存和显存之前拷贝往往会造成性能瓶颈&#xff0c;而利用 PBO 可以在一定程度上解决这个问题。 PBO &#xff08;Pixel Buffer Object&#xff09;是 OpenGL ES 3.…

iOS开发提效cocoapods插件cocoapods-util

cocoapods-util介绍 cocoapods-util是一个iOS开发提效的cocoapods插件。 取名util的原因是我想做一个通用的插件&#xff0c;把一些iOS中常用的命令或问题整理起来。 插件中除了package命令是根据cocoapods-packager插件做了修改而来&#xff0c;其余命令都是属于自己总结开…

uwb高精度定位系统源码 UWB高精度定位技术原理与实现

uwb高精度定位系统 UWB高精度定位技术原理与实现 近些年物联网产业高速发展&#xff0c;越来越多的物联网终端连上了网络&#xff0c;实现了人与物&#xff0c;甚至物与物之间的互连互通。随着智能化要求的进一步提高和物联网应用的进一步拓展&#xff0c;除了互联互通&#x…

Doxygen源码分析:doxygen执行过程的拆解

Doxygen源码分析&#xff1a;doxygen执行过程的拆解 2023-05-19 23:09:17 ~ 2023-05-20 16:38:13 ChrisZZ imzhuofoxmailcom Hompage https://github.com/zchrissirhcz 文章目录 Doxygen源码分析&#xff1a;doxygen执行过程的拆解1. doxygen 版本2. doxygen 可执行程序的入口…

System V方案 — 共享内存

目录 System V方案 — 详述共享内存共享内存共享内存的原理共享内存数据结构共享内存函数实例 消息队列消息队列数据结构消息队列函数创建删除 信号量信号量数据结构信号量函数创建删除 进程互斥 总结 System V方案 — 详述共享内存 SystemV标准的进程间通信方式&#xff0c;是…

【react 全家桶】react-Hook(上)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 14【react-Hook &#xff08;上&#x…

计算机网络基础知识(六)—— 什么是HTTP协议?你听我说

文章目录 01 | 基本概念02 | 工作原理 && 特点03 | URI && URL04 | 消息结构05 | 请求方法06 | http响应头信息07 | 状态码08 | HTTP的常见安全机制09 | HTTP的缓存机制10 | HTTP/2 && HTTP/3新特性11 | 面试中常见问题 超文本传输协议&#xff08;Hyp…

【前端知识】Cookie, Session,Token和JWT的发展及区别(四)

【前端知识】Cookie, Session,Token和JWT的发展及区别&#xff08;四&#xff09; 9. JWT9.1 JWT的背景及定义&#xff08;1&#xff09;JWT的字面理解&#xff08;2&#xff09;JWT与传统Token的区别 9.2 JWT的组成&#xff08;1&#xff09; Header&#xff08;头部&#xff…

【UDS】诊断故障代码老化机制

文章目录 简介相关术语1. 老化计数器 Ageing counter2. 诊断故障代码已老去 DTC aged3. 已老去计数器 Aged counter4. 操作循环 Operation cycle5. 诊断故障代码老化机制 DTC aging mechanism 总结 ->返回总目录<- 简介 诊断故障代码&#xff08;DTC&#xff09;一旦生…

【IDEA使用指南】使用Hibernate框架的Java项目,如何找到并打开 “Import Database Schema”窗口?

【IDEA使用指南】使用Hibernate框架的Java项目&#xff0c;如何找到并打开 “Import Database Schema”窗口&#xff1f; 背景&#xff1a; 使用 Hibernate 框架时&#xff0c;假如在 “Import Database Schema” 窗口&#xff08;如下图所示&#xff09;时&#xff0c;点击了…

day06_Java中的流程控制语句

流程控制 简单来讲所谓流程就是完成一件事情的多个步骤组合起来就叫做一个流程。在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能…

.Net6 使用aspose.cells23.5.0破译

一、测试代码 internal class Program { static void Main(string[] args) { WorkbookDesigner wb new WorkbookDesigner(new Workbook()); var style new CellsFactory().CreateStyle(); style.Borders.SetColor(C…

路径规划算法:基于缎蓝园丁鸟算法的路径规划算法- 附代码

路径规划算法&#xff1a;基于缎蓝园丁鸟优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于缎蓝园丁鸟优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能…

交换式以太网的诞生

电路交换&#xff0c;终端(电话)独占端线路自然而然&#xff0c;天经地义&#xff0c;可计算机收发的是数据包(即数据分组)&#xff0c;当多台终端接入到同一个共享介质的网络&#xff0c;所有终端可 “同时” 收发数据&#xff0c;一起统计复用网络&#xff0c;多台终端如何协…

Linux常用命令——htop命令

在线Linux命令查询工具 htop [非内部命令]一个互动的进程查看器&#xff0c;可以动态观察系统进程状况。 补充说明 htop命令 是Linux系统中的一个互动的进程查看器&#xff0c;一个文本模式的应用程序(在控制台或者X终端中)&#xff0c;需要ncurses。 与Linux传统的top相比…

【5.20】五、安全测试——概念与漏洞

目录 5.1 安全测试概述 5.1.1 什么是安全测试 5.1.2 安全测试的基本原则 5.2 常见的安全漏洞 5.2.1 SQL注入 5.2.2 XSS跨站脚本攻击 5.2.3 CSRF攻击 软件安全测试是软件测试的重要研究领域&#xff0c;它是保证软件能够安全使用的最主要手段&#xff0c;做好软件安全测试…

pg事务:multixact

什么是multixact&#xff1f; 在对同一行加锁时&#xff0c;元组上关联的事务ID可能有多个&#xff0c;pg将多个事务ID组合起来用一个MultiXactID来管理。TransactionId和MultiXactID是多对一的关系 multixactID跟TransactionId一样&#xff0c;也是32位&#xff0c;同样有wra…