【算法与数据结构】28、LeetCode实现strStr函数

news/2024/5/19 16:10:40/文章来源:https://blog.csdn.net/qq_45765437/article/details/131488300

文章目录

  • 一、题目
  • 二、暴力穷解法
  • 三、KMP算法
  • 四、Sunday算法
  • 五、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述

二、暴力穷解法

  思路分析:首先判断字符串是否合法,然后利用for循环,取出子字符串利用compare函数进行比较。
  程序如下

class Solution {
public:// 复杂度n * mint strStr(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;	if (!needle.size()) return 0; // needle为空返回0for (int i = 0; i < haystack.size(); ++i) {string substr = haystack.substr(i, needle.size());if (!needle.compare(substr)) return i;}return -1;}
};

复杂度分析:

  • 时间复杂度: O ( n ∗ m ) O(n * m) O(nm),假设haystack的长度为n,needle的长度为m,for循环的复杂度为n,当中调用了compare函数,它是逐字符比较的,复杂度为m,因此总复杂度为 O ( n ∗ m ) O(n * m) O(nm)
  • 空间复杂度: O ( 1 ) O(1) O(1)

三、KMP算法

  思路分析:这个算法比较著名了,简单来讲就是建立前缀表,然后进行匹配,匹配失败就根据前缀表找到下一个模式串的位置。具体的思路可以看看笔者的这片文章【算法与数据结构】字符串匹配算法。
  程序如下

	// KMP算法void getNext(int* next, const string& s) {int j = -1;next[0] = j;for (int i = 1; i < s.size(); i++) { // 注意i从1开始while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了j = next[j]; // 向前回退}if (s[i] == s[j + 1]) { // 找到相同的前后缀j++;}next[i] = j; // 将j(前缀的长度)赋给next[i]}}int strStr2(string haystack, string needle) {if (needle.size() == 0) {return 0;}int* next = new int[needle.size()];//int next[needle.size()]; getNext(next, needle);//my_print(next, needle.size(), "前缀表:");int j = -1; // // 因为next数组里记录的起始位置为-1for (int i = 0; i < haystack.size(); i++) { // 注意i就从0开始while (j >= 0 && haystack[i] != needle[j + 1]) { // 不匹配j = next[j]; // j 寻找之前匹配的位置}if (haystack[i] == needle[j + 1]) { // 匹配,j和i同时向后移动j++; // i的增加在for循环里}if (j == (needle.size() - 1)) { // 文本串s里出现了模式串treturn (i - needle.size() + 1);}}return -1;}

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n + m) O(n+m),其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的。
  • 空间复杂度: O ( m ) O(m) O(m),需要额外的空间存放大小为m的数组。

四、Sunday算法

  思路分析:思路部分大家也可以看笔者的这篇文章【算法与数据结构】字符串匹配算法。第二个版本的算法相对来说简洁快速一些。
  程序如下

    // Sunday算法int find_single_char(char c, const string& needle) {   for (int i = needle.size() - 1; i >= 0; --i) {  // 找最右端的字符,因此从后往前循环if (c == needle[i]) return i; }return -1;}int strStr3(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;     // 检查合法性if (!needle.size()) return 0;                       // needle为空返回0      for (int i = 0; i <= haystack.size() - needle.size(); ) {for (int j = 0; j < needle.size(); ++j) {if (needle[j] != haystack[i + j]) {     // 匹配失败                int k = find_single_char(haystack[i + needle.size()], needle);   // 文本字符串末尾的下一位字符串if (k == -1)   i += needle.size() + 1;  // 模式串向右移动 模式串长度 + 1 else i += needle.size() - k;            // 向右移动 模式串最右端的该字符到末尾的距离+1break;}     if (j == needle.size() - 1) return i;   // 匹配成功}}return -1;}
    // 查找算法用哈希表代替的Sunday算法   int strStr4(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;     // 检查合法性if (!needle.size()) return 0;                       // needle为空返回0  int shift_table[128] = { 0 };       // 128为ASCII码表长度for (int i = 0; i < 128; i++) {     // 偏移表默认值设置为 模式串长度 + 1shift_table[i] = needle.size() + 1;}for (int i = 0; i < needle.size(); i++) {	// 如果有重复字符也会覆盖,确保shift_table是 模式串最右端的字符到末尾的距离 + 1shift_table[needle[i]] = needle.size() - i;}int s = 0; // 文本串初始位置// 模式串已经匹配到的位置int j;while (s <= haystack.size() - needle.size()) {j = 0;while (haystack[s + j] == needle[j]) { ++j;if (j >= needle.size()) return s;   // 匹配成功}// 找到主串中当前跟模式串匹配的最末字符的下一个字符// 在模式串中出现最后的位置// 所需要从(模式串末尾+1)移动到该位置的步数s += shift_table[haystack[s + needle.size()]];}// 输出结果return -1;}

复杂度分析:

  • 时间复杂度: 平均时间复杂度为 O ( n ) O(n) O(n),最坏情况时间复杂度为 O ( n ∗ m ) O(n*m) O(nm)
  • 空间复杂度: O ( 1 ) O(1) O(1)

五、完整代码

# include <iostream>
# include <string>
using namespace std;void my_print(int* arr, int arr_len, string str) {cout << str << endl;for (int i = 0; i < arr_len; ++i) {cout << arr[i] << ' ';}cout << endl;
}class Solution {
public:// 暴力穷解// 复杂度n * mint strStr(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;	if (!needle.size()) return 0; // needle为空返回0for (int i = 0; i < haystack.size(); ++i) {string substr = haystack.substr(i, needle.size());if (!needle.compare(substr)) return i;}return -1;}// KMP算法void getNext(int* next, const string& s) {int j = -1;next[0] = j;for (int i = 1; i < s.size(); i++) { // 注意i从1开始while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了j = next[j]; // 向前回退}if (s[i] == s[j + 1]) { // 找到相同的前后缀j++;}next[i] = j; // 将j(前缀的长度)赋给next[i]}}int strStr2(string haystack, string needle) {if (needle.size() == 0) {return 0;}int* next = new int[needle.size()];//int next[needle.size()]; getNext(next, needle);//my_print(next, needle.size(), "前缀表:");int j = -1; // // 因为next数组里记录的起始位置为-1for (int i = 0; i < haystack.size(); i++) { // 注意i就从0开始while (j >= 0 && haystack[i] != needle[j + 1]) { // 不匹配j = next[j]; // j 寻找之前匹配的位置}if (haystack[i] == needle[j + 1]) { // 匹配,j和i同时向后移动j++; // i的增加在for循环里}if (j == (needle.size() - 1)) { // 文本串s里出现了模式串treturn (i - needle.size() + 1);}}return -1;}// Sunday算法int find_single_char(char c, const string& needle) {   for (int i = needle.size() - 1; i >= 0; --i) {  // 找最右端的字符,因此从后往前循环if (c == needle[i]) return i; }return -1;}int strStr3(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;     // 检查合法性if (!needle.size()) return 0;                       // needle为空返回0      for (int i = 0; i <= haystack.size() - needle.size(); ) {for (int j = 0; j < needle.size(); ++j) {if (needle[j] != haystack[i + j]) {     // 匹配失败                int k = find_single_char(haystack[i + needle.size()], needle);   // 文本字符串末尾的下一位字符串if (k == -1)   i += needle.size() + 1;  // 模式串向右移动 模式串长度 + 1 else i += needle.size() - k;            // 向右移动 模式串最右端的该字符到末尾的距离+1break;}     if (j == needle.size() - 1) return i;   // 匹配成功}}return -1;}
};int main()
{//string haystack = "sadbutsad";//string needle = "sad";//string haystack = "abc";//string needle = "c";//string haystack = "substring searching algorithm";//string needle = "search";//string haystack = "hello";//string needle = "ll";//string haystack = "mississippi";//string needle = "issi";string haystack = "aabaaaababaababaa";string needle = "bbbb";int k = 2;Solution s1;cout << "目标字符串:\n" << "“" << haystack << "”" << endl;int result = s1.strStr3(haystack, needle);cout << "查找子串结果:\n" << result << endl;system("pause");return 0;
}

end

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

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

相关文章

Docker发布JAVA vhr微人事后端(确保打包没问题再发布)

本文代码来源于&#xff08;感谢作者&#xff09; GitHub - lenve/vhr: 微人事是一个前后端分离的人力资源管理系统&#xff0c;项目采用SpringBootVue开发。1.创建DockerFile文件 创建mail文件夹 创建web文件夹 以下为mail dockerfile FROM java:8 Add *.jar /app/app.ja…

【深度学习】AIGC ,ControlNet 论文,原理,训练,部署,实战,教程

论文&#xff1a;https://arxiv.53yu.com/pdf/2302.05543 代码&#xff1a;https://github.com/lllyasviel/ControlNet 得分几个博客完成这个事情的记录了&#xff0c;此篇是第一篇&#xff0c;摘录了一些论文内容。ControlNet 的原理极为朴实无华&#xff08;对每个block添加…

vue3+ts+elementui制作精美的课表

使用vue3tselementui 如何制作出精美的课表呢&#xff0c; 最终效果图如下: 直接上代码&#xff1a; 这里直接把封装成一个课表的组件&#xff1a; <script setup lang"ts"> import { ref, watch, onMounted } from "vue"; import IconText from …

Android Studio实现内容丰富的安卓志愿者平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号122 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.…

网页的动静分离设置

我们都知道nginx处理静态网页是强项,而tomcat处理动态网页是强项.我们可以发挥他们共同的优点.nginx处理静态页面而tomcat处理动态页面 进入nginx配置文件改 总结 1.改配置文件最好复制一份 2.做一步验证一步 才知道哪里出错了 3.出错了别着急先看页面在浏览器能不能打开 不…

nRF52832蓝牙概述

基本概念 RSSI&#xff08;Received Signal Strength Indicator&#xff09;是接收信号的强度指示。 接收包RSSI是指无线模块发送信息后&#xff0c;接收端的无线模块接收到数据后&#xff0c;当前接收数据的信号强度的寄存器值&#xff0c;也就是接收模块获取到发送模块当前发…

【Verilog HDL】FPGA-testbench基础知识

&#x1f389;欢迎来到FPGA专栏~testbench基础知识 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家能…

20230704测试STC32G实验箱9.6(STC32G12K128)开发板的虚拟串口(C语言深入了解)

20230704测试STC32G实验箱9.6&#xff08;STC32G12K128&#xff09;开发板的虚拟串口&#xff08;C语言深入了解&#xff09; 06第五集&#xff1a;C语言运算符和进制数入门上.mp4 07第五集&#xff1a;C语言运算符和进制数入门下.mp4 2023/7/4 19:00 下次 在【冲哥】录视频的时…

PSI算法极简概述

什么是隐私求交PSI 隐私求交是多方安全计算中的密码学技术&#xff0c;它允许数据持有方通过比较加密集合计算得到交集&#xff0c;且任何一方都不会获得其他信息。PSI还存在一种变体&#xff0c;即CS场景。客户端可以获取其与服务器的交集但是服务器无法学习到该集合。如果在…

netty学习(2):多个客户端与服务器通信

1. 基于前面一节netty学习&#xff08;1&#xff09;:1个客户端与服务器通信 只需要把服务器的handler改造一下即可&#xff0c;通过ChannelGroup 找到所有的客户端channel&#xff0c;发送消息即可。 package server;import io.netty.channel.*; import io.netty.channel.gr…

Android Studio实现内容丰富的安卓汽车租赁平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号101 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查…

登录校验-Filter/过滤器

过滤器 概念&#xff1a;Filter过滤器&#xff0c;是javaweb的三大组件&#xff08;servlet,Filter,Listener&#xff09;之一 作用&#xff1a;可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能 过滤器的常见操作&#xff1a;登录校验&#xff0c;统一编码&…

Word公式大括号左对齐

1、大括号公式如下&#xff1a; 2、依次选中每一行&#xff0c;然后在开头输入一个&&#xff0c;然后回车&#xff1a; 3、当最后一行输入完立马可以发现左对齐了&#xff1a; The higher I got, the more amazed I was by the view.

win下实现Linux的tab自动补全

声明 &#xff1a;如果不是确定的话 注册表这个东西不建议更改 如果更改的话建议先备份系统 以防意外 1.找到注册表编辑器 2. 展开HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor 3.找到Completion Char 双击 把橙色的数值改成9 4.重新打开cmd 就可以了 参考文章…

github上传超过100M的大文件

当上传的工程中有超过100M的文件时&#xff0c;直接上传github会产生如下报错&#xff1a; remote: error: File retinaface-R50/R50-0000.params is 112.54 MB; this exceeds GitHubs file size limit of 100.00 MB! [remote rejected] master -> master (pre-receive ho…

vue打包到生产环境

1.进入到项目根目录执行 npm run build此时会自动打包在dist目录下 2.安装服务 npm install -g serve3.启动 serve dist以上是生产环境打包的过程。 npm run dev 是开发环境, npm run build 是生产环境

微软发布「升级版」多模态大模型 Kosmos-2!新增局部理解能力,解锁实体级交互

夕小瑶科技说 原创 作者 | 小戏、ZenMoore 三个多月前&#xff0c;微软亚洲研究院在论文《Language Is Not All You Need: Aligning Perception with Language Models》中发布了一个强大的多模态大模型 Kosmos-1&#xff0c;成功将感知与语言对齐&#xff0c;在 ChatGPT 的多…

银河麒麟服务器v10 sp1 安装mysql

可以先用 dpkg --list|grep mysql 查看自己的mysql有哪些依赖&#xff1a; 上图已经是安装后的截图&#xff0c;然后再卸载 sudo apt-get autoremove --purge mysql-common 本文在没有安装之前&#xff0c;只有mysql-common包&#xff0c;再用dpkg --list|grep mysql查看&…

HTML5开发工程师岗位的职责说明文(合集)

HTML5开发工程师岗位的职责说明文1 职责&#xff1a; 1、根据产品设计文档和视觉文件&#xff0c;利用HTML5&#xff0c;Javascript相关技术实现web端的界面效果、交互和功能; 2、基于HTML5.0的标准进行页面制作&#xff0c;编写可复用的用户界面组件; 3、负责分析和解决前端…

【Java从入门到大牛】Java快速入门

目录 简单认识JavaJava背景知识Java能做什么Java技术体系 如何使用Java搭建Java开发环境总结 开发第一个Java程序开发过程HelloWorld案例常见错误总结 Java程序的执行原理总结 JDK的组成和跨平台原理JDK的组成Java的跨平台、工作原理总结 JDK安装后设置Path和Java_home环境变量…