模式串匹配和字符串哈希

目录

一、字符串暴力匹配

二、字符串哈希解决匹配问题

不使用哈希的递归版本

使用哈希的版本

 


不太懂哈希表的可以看我上一篇文章。

哈希表及其基础(java详解)-CSDN博客

一、字符串暴力匹配

public class SubstringMatch {//构造函数设置成私有的,不会被创建对象private SubstringMatch(){}//暴力匹配 源字符串s和目标字符串t//在s中寻找t,返回匹配到的第一个索引i,没找到就返回-1public static int bruteforce(String s, String t) {if (s.length() < t.length()) {return -1;}//s[i, i + t.length - 1] == t ?for (int i = 0; i + t.length() - 1 < s.length(); i++) {int j = 0;for (; j < t.length(); j++) {if (s.charAt(i + j) != t.charAt(j))break;if (j == t.length() - 1) return i; // 修改这里}}return -1;}public static void main(String[]args){String s1 = "hello, yujing.";String t1 = "yujing";System.out.println(SubstringMatch.bruteforce(s1, t1));}
}

二、字符串哈希解决匹配问题

 扔掉匹配问题不看,看字符串转哈希思想的一个应用。

1147. 段式回文 - 力扣(LeetCode)

你会得到一个字符串 text 。你应该把它分成 k 个子字符串 (subtext1, subtext2,…, subtextk) ,要求满足:

  • subtexti 是 非空 字符串
  • 所有子字符串的连接等于 text ( 即subtext1 + subtext2 + ... + subtextk == text )
  • 对于所有 i 的有效值( 即 1 <= i <= k ) ,subtexti == subtextk - i + 1 均成立

返回k可能最大值。

 

示例 1:

输入:text = "ghiabcdefhelloadamhelloabcdefghi"
输出:7
解释:我们可以把字符串拆分成 "(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)"。

示例 2:

输入:text = "merchant"
输出:1
解释:我们可以把字符串拆分成 "(merchant)"。

示例 3:

输入:text = "antaprezatepzapreanta"
输出:11
解释:我们可以把字符串拆分成 "(a)(nt)(a)(pre)(za)(tep)(za)(pre)(a)(nt)(a)"。

提示:

  • 1 <= text.length <= 1000
  • text 仅由小写英文字符组成

根据题目,我们要尽可能多的把字符串划分成几段,第一段和最后一段字符串相等,第二段和倒数第二段字符串相等,如果分成奇数个那么最中间的一段不需要和任何段相等。

不使用哈希的递归版本

//不使用哈希的递归版本 O(N^2)
public class Solution {public int longestDecomposition(String text){return solve(text, 0, text.length() - 1);}//s[left, right]//left从左往右走 right从右往左走private int solve(String s, int left, int right){if(left > right) return 0;for(int i = left, j = right; i < j; i++, j--){//s[left, i] == s[j, right]if(equal(s, left, i, j, right))return 2 + solve(s, i + 1, j - 1);}return 1;}//s[l1, r1] == s[l2, r2] ?private boolean equal(String s, int l1, int r1, int l2, int r2){for(int i = l1, j = l2; i <= r1 && j <= r2; i++, j++)if(s.charAt(i) != s.charAt(j)) return false;return true; }
}

使用哈希的版本

基于哈希的思路代码整体框架和上一个不使用哈希的递归版本是一样的,区别在于给两个字符串判等的时候我们比较的是两个子串对应的哈希值,对于这两个哈希值我们不是每一次都计算一遍,不然整体还会是一个O(N^2)级别的算法。我们做的是要根据前一次计算的哈希值只通过一次计算来推导出当我们拿到新的左边的第i个字符和右边的第j个字符之后,这个新的哈希值是谁。即下图的方式。

//使用哈希 O(N)
public class Solution {private long MOD = (long)(1e9 + 7);//即十亿零七private long[] pow26;public int longestDecomposition(String text){//预处理操作,提前把26的各个次方数值存进去,用到哪个就直接提哪个//pow26[i] = 26^i//虽然这样做多用了空间,但在算法里时间比空间值钱,我们愿意用时间换空间pow26 = new long[text.length()];pow26[0] = 1;for(int i = 1; i < text.length(); i++){//求余是为了防止整型溢出pow26[i] = pow26[i - 1] * 26 % MOD;}return solve(text, 0, text.length() - 1);}//s[left, right]//left从左往右走 right从右往左走private int solve(String s, int left, int right){if(left > right) return 0;long prehash = 0, posthash = 0;for(int i = left, j = right; i < j; i++, j--){//(s.charAt(i) - 'a')代表a对应0,b对应1,c对应2....prehash = (prehash * 26 + (s.charAt(i) - 'a')) % MOD;posthash = ((s.charAt(j) - 'a') * pow26[right - j] + posthash) % MOD;//s[left, i] == s[j, right]if(prehash == posthash && equal(s, left, i, j, right))return 2 + solve(s, i + 1, j - 1);}return 1;}//s[l1, r1] == s[l2, r2] ?private boolean equal(String s, int l1, int r1, int l2, int r2){for(int i = l1, j = l2; i <= r1 && j <= r2; i++, j++)if(s.charAt(i) != s.charAt(j)) return false;return true;}
}

在提交到leetcode后我们发现哈希的解法却比递归的慢,因为leetcode的测试样例的数据量不够大,反而显得哈希方法比较慢,如果数据量够大,哈希法的性能就能体现出来了。 

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

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

相关文章

Day15——File类与IO流

1.java.io.File类的使用 1.1 File类的理解 File 类及本章下的各种流&#xff0c;都定义在 java.io 包下。一个 File 对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆对象&#xf…

Prometheus 配置文件和标签 Pmsql

1.Prometheus配置文件 Prometheus可以通过命令行或者配置文件的方式对服务进行配置。 命令行方式一般用于不可变的系统参数配置&#xff0c;例如存储位置、要保留在磁盘和内存中的数据量等&#xff1b;配置文件用于定义与数据动态获取相关的配置选项和文件等内容。命令行方式…

arm 交叉编译器版本下载

网址&#xff1a;https://releases.linaro.org/components/toolchain/binaries/ 根据板子架构选择正确的编译器 根据你主机架构选择对应的版本&#xff08;就是你的开发电脑架构&#xff09;

3.PyTorch——常用神经网络层

import numpy as np import pandas as pd import torch as t from PIL import Image from torchvision.transforms import ToTensor, ToPILImaget.__version__2.1.13.1 图像相关层 图像相关层主要包括卷积层&#xff08;Conv&#xff09;、池化层&#xff08;Pool&#xff09;…

自然语言处理基础知识 学习

参考&#xff1a;OpenBMB - 让大模型飞入千家万户 【清华NLP】刘知远团队大模型公开课全网首发&#xff5c;带你从入门到实战_哔哩哔哩_bilibili 图灵测试&#xff1a;imitation Game 模仿游戏 Part of speech tagging 词性标注 Named entity recognition &#xff1a; 命名…

第54天:django学习(三)

页面上的增删改查 创建一个django项目&#xff08;使用django3版本&#xff09;day54——dj&#xff0c;并创建应用app01 在models.py文件中创建表 class UserInfo(models.Model):username models.CharField(max_length32)password models.CharField(max_length32)gender m…

Ribbon组件的负载均衡原理

原因背景 spring cloud的底层负载均衡是采用Ribbon组件&#xff0c;我们将user-service服务注册到eureka-server中&#xff0c;那么当我们在另一个服务的代码层面请求远程调用API接口http://user-service/users/5时&#xff0c;程序代码如何解析远程调用的user-service服务名转…

快速排序的非递归实现

上期我们实现了快速排序的递归实现&#xff0c;但是我们知道如果递归深度太深&#xff0c;栈就会溢出&#xff0c;所以我们本期将为大家讲述快速排序的非递归实现&#xff0c;我们需要用到栈的数据结构&#xff0c;我们知道栈中的数据全是在堆区开辟的空间&#xff0c;堆的空间…

VS2015编译GDAL3.2.0+opencl+C#

参考借鉴https://www.cnblogs.com/litou/p/15004877.html 参考借鉴https://www.cnblogs.com/xiaowangba/p/6313903.html 参考借鉴gdal、proj、geos、sqlite等在VS2015下编译和配置_vs2015编译sqlite3-CSDN博客 参考借鉴Windows下GDAL3.1.2编译 (VS2015)_gdal windows编译-CS…

【动手学深度学习】(十)PyTorch 神经网络基础+GPU

文章目录 一、层和块1.自定义块2.顺序块3.在前向传播函数中执行代码 二、参数管理1.参数访问2.参数初始化3.参数绑定 三、自定义层1.不带参数的层2.带参数的层 四、读写文件1.加载和保存张量2.加载和保存模型参数五、使用GPU [相关总结]state_dict() 一、层和块 为了实现复杂神…

机器学习---线性回归案例

1、梯度下降法调节参数 2、模拟过拟合 训练模型都会将数据集分为两部分&#xff0c;一般会将0.8比例的数据集作为训练集&#xff0c;将0.2比例的数据集作为测试集&#xff0c;来训练模型。模型过拟合就是训练出来的模型在训练集上表现很好&#xff0c;但是在测试集上表现较差的…

架构师进阶,微服务设计与治理的 16 条常用原则

今天将从存储的上一层「服务维度」学习架构师的第二项常用能力 —— 微服务设计与治理。 如何设计合理的微服务架构&#xff1f; 如何保持微服务健康运行&#xff1f; 这是我们对微服务进行架构设计过程中非常关注的两个问题。 本文对微服务的生命周期定义了七个阶段&#x…