字符串哈希-最易懂的证明

文章目录

    • 题目
    • 题目解析:
    • 解题思路:
    • 具体算法
      • 为什么?举个例子
      • 再举个例子
    • 代码:

题目


给定一个长度为 n的字符串,再给定 m个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1]和 [l2,r2]
这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

输入格式
第一行包含整数 n 和 m,表示字符串长度和询问次数。

第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。

接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。

注意,字符串的位置从 1开始编号。

输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No。

每个结果占一行。

数据范围
1 ≤ n,m ≤ 105
输入样例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

输出样例:

Yes
No
Yes

题目解析:

给出一个字符串,例如 s = "adcdabcde"
给出[l1, r1][l2, r2]
问字符串的子串 s[l1, r1] s[l2, r2] 是否相同

解题思路:

  1. 思路一:暴力,超时。

  2. 思路二:字符串哈希

将字符串转换成一个P进制的数字,例如 131 进制的数字。这个值看做字符串的哈希值h。

相同的字符对应的P进制数字一定相同,即哈希值相同。

因为进制取得131,认为哈希值相同的字符是相等的。

因此,只要能快速求出s[l1, r1]s[l2,r2]对应的字符串的哈希值h[s[l1, r1]] h[s[l2, r2]],并判断是否相等。就能得出l1, r1 l2,r2对应的字符串是否相同

具体算法

如何快速求出s[l, r]的哈希值h[s[l,r ]]是关键。这里可以使用前缀和思想。

字符串s的下标从1开始,字符串长度为n。P 取131。字符串s[1, t]对应的哈希值记为h[t]

  1. 分别求出 h[1], h[2], h[3],h[n]

  2. 此时

 h[s[l, r]] = h[r] - h[s[l - 1]] * pow(131, r - l + 1)

为什么?举个例子

例如s = "abcabcd", 各个位置对应的数字为:

s = "97 98 99 97 98 99 100"
h[1] = 97
h[2] = h[1] * P + h['b'] = 97 * 131 + 98 = 12,805
h[3] = h[2] * P + h['c'] = 12805*131 + 99 = 1,677,554
h[4] = h[3] * P + h['a'] = 1,677,554 * 131 + 97 = 219,759,671‬
h[5] = h[4] * P + h['b'] = 219,759,671* 131 + 98 =28,788,516,999‬
h[6] = h[5] * P + h['c'] = 28,788,516,999* 131 + 99 = 3,771,295,726,968
h[7] = h[6] * P + h['d'] = 3,771,295,726,968 * 131 + 100 = 494,039,740,232,908

h[s[2, 3]]

  1. h[3] = h['abc'] = h['a'] * pow(P, 2) + h['b'] * pow(P, 1) + h['c'] = 1,677,554

  2. h[1] = h['a'] = 97

  3. h[s[2, 3]] = h['bc'] = h['b'] * pow(P, 1) + h['c']

  4. 所以:h[s[2, 3]]= h[3] - h[1] * pow(P, 2) = 12,937‬

  5. 也就是:h[s[l, r]] = h[r] - h[l - 1] * pow(P, r - l + 1)

再举个例子

以s为数字字符串,各个位置的值等于数字本身,P等于10,说明h[s[l, r]] = h[r] - h[s[l - 1]] * pow(P, r - l + 1)

s = '4564'
h[1] = 4
h[2] = 45
h[3] = 456
h[4] = 4565
h[s[2,3]] = 456 - 4 * 100 = h[3] - h[1] * pow(10, 2)

代码:

C++代码

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5+5,P = 131;//131 13331
ULL h[N],p[N];// h[i]前i个字符的hash值
// 字符串变成一个p进制数字,体现了字符+顺序,需要确保不同的字符串对应不同的数字
// P = 131 或  13331 Q=2^64,在99%的情况下不会出现冲突
// 使用场景: 两个字符串的子串是否相同
ULL query(int l,int r){return h[r] - h[l-1]*p[r-l+1];
}
int main(){int n,m;cin>>n>>m;string x;cin>>x;//字符串从1开始编号,h[1]为前一个字符的哈希值p[0] = 1;h[0] = 0;for(int i=0;i<n;i++){p[i+1] = p[i]*P;            h[i+1] = h[i]*P +x[i];      //前缀和求整个字符串的哈希值}while(m--){int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;if(query(l1,r1) == query(l2,r2)) printf("Yes\n");else printf("No\n");}return 0;
}

Python代码

import sys
n, m = map(int, sys.stdin.readline().split())
P = 131
s = input()
Q = 1 << 64
h = [0] * (len(s) +  10)
p = [0] * (len(s) +  10)
p[0] = 1
s = " " + s
# 根据公式求
def get(l, r):return (h[r] - h[l - 1] * p[r - l + 1]) % Q# 初始化
for i in range(1, len(s)):h[i] = (h[i - 1] * P + ord(s[i])) % Qp[i] = p[i - 1] * P % Qwhile m:m -= 1l1, r1, l2, r2 = map(int, input().split())if get(l1, r1) == get(l2, r2):print("Yes")else:print("No")

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

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

相关文章

再学Java基础——反射

Java中的反射&#xff08;Reflection&#xff09;是一种强大的工具&#xff0c;它允许程序在运行时检查类、接口、字段和方法的信息&#xff0c;并且允许对这些对象进行实例化、调用等操作。这种能力使Java代码具有高度的动态性和灵活性。 反射的基本概念 反射提供了以下功能…

Baumer工业相机堡盟工业相机如何通过NEOAPISDK获取相机的Statistics图像传输统计信息(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPISDK获取相机的Statistics图像传输统计信息&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机NEOAPI SDK和相机Statistics图像传输统计信息的技术背景Baumer工业相机通过NEOAPISDK获取相机的Statistics图像传输统计信息技术1.引…

重看Spring聚焦BeanDefinition分析和构造

目录 一、对BeanDefinition的理解 &#xff08;一&#xff09;理解元信息 &#xff08;二&#xff09;BeanDefinition理解分析 二、BeanDefinition的结构设计分析 &#xff08;一&#xff09;整体结构体会 &#xff08;二&#xff09;重要接口和类分析 三、构造 BeanDef…

搭建MongoDB分片集群

文章目录 一、什么是分片二、分片集群1、组件构成2、分片集群内各组件间交互 三、数据如何切分四、分片策略1、哈希分片2、范围分片 五、分片集群架构六、搭建分片集群1、涉及主机2、所有主机安装MongoDB3、分片节点副本集的创建3.1、第一套副本集shard13.1.1、准备存放数据和日…

课时114:sed命令_进阶实践_高阶用法1

2.2.3 高阶用法1 学习目标 这一节&#xff0c;我们从 基础知识、缓存实践、小结 三个方面来学习。 基础知识 简介 对于sed命令来说&#xff0c;除了我们经常使用的模式空间之外&#xff0c;它还支持一个叫暂存空间(Hold Space)的模式,所谓的暂存空间&#xff0c;也就是说&a…

计算机网络期末试题

第一章 概述 一. 单选题&#xff08;共13题&#xff0c;36.4分&#xff09; 1. (单选题) 因特网起源于( &#xff09;网络。 A. ARPANETB. EthernetC. CATVD. CERNET 我的答案: A:ARPANET;正确答案: A:ARPANET; 2.8分 2. (单选题)人们把( &#xff09;年作为因特网的诞…

从零开始搭建一个vue项目

从零开始搭建一个vue项目 一、环境准备 1.1 安装node.js 选择合适的LTS版本&#xff0c;然后下载安装&#xff0c;安装地址&#xff1a;https://nodejs.org/en/download 在命令行中查看已安装的node.js版本 node -v v14.14.01.2 切换为淘宝的镜像源 解决国内下载慢的问题,…

(五)SQL系列练习题(上)创建、导入与查询 #CDA学习打卡

目录 一. 创建表 1&#xff09;创建课程表 2&#xff09;创建学生表 3&#xff09;创建教师表 4&#xff09;创建成绩表 二. 导入数据 1&#xff09;导入课程科目数据 2&#xff09;导入课程成绩数据 3&#xff09;导入学生信息数据 4&#xff09;导入教师信息数据 …

Mac OS 笔记

rvm、Ruby、gem、CocoaPods的安装与卸载 安装rvm curl -fsSL https://get.rvm.io | bash -s stable --ruby --autolibsenable --auto-dotfilesrvm -v # 查看版本安装脚本 /usr/bin/ruby -e "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install…

决策树算法

目录 决策树的应用决策树算法分类决策树算法开源实现决策树的使用 决策树是一种常用的数据挖掘方法&#xff0c;它是一种树形结构的算法&#xff0c;用于决策分析和预测。 决策树由节点和分支构成&#xff0c;其中节点分为内部节点和叶节点两种。内部节点表示一个特征或属性&a…

《金融研究》:普惠金融改革试验区DID工具变量数据(2012-2023年)

数据简介&#xff1a;本数据集包括普惠金融改革试验区和普惠金融服务乡村振兴改革试验区两类。 其中&#xff0c;河南兰考、浙江宁波、福建龙岩和宁德、江西赣州和吉安、陕西铜川五省七地为普惠金融改革试验区。山东临沂、浙江丽水、四川成都三地设立的是普惠金融服务乡村振兴…

【bbs02补】注册功能form组件-前端-后端-总结、登录功能(前端、后端、生成验证码)

1 注册功能 1.1 注册功能form组件 1.2 注册功能前端 1.3 注册功能后端 1.4 forms组件和前后端总结 2 登录功能 2.1 登录前端 2.2 生成验证码 1 注册功能 1.1 注册功能form组件 # 注册页面-用户名-密码-确认密码-邮箱-手机号-头像# form组件 可以帮助我们1 快速生成前端页面2 数…

Xamarin.Android项目显示Properties

在 Visual Studio 2022 中&#xff0c;如果您需要调出“Properties”&#xff08;属性&#xff09;窗口&#xff0c;您可以使用以下几种方法&#xff1a; 快捷键&#xff1a; 您可以按 F4 快速打开当前选择项的“Properties”窗口。

pytorch笔记:ReplicationPad1d

torch.nn.ReplicationPad1d(padding) 在 PyTorch 中&#xff0c;ReplicationPad1d 是一种用于一维数据的填充层该层通过复制序列的边缘值来增加数据的长度&#xff0c;这在卷积神经网络中常用于保持数据尺寸主要参数 padding 可以是一个整数或一个元组。 如果是一个整数&…

Python 植物大战僵尸

文章目录 效果图项目结构实现思路源代码 效果图 项目结构 实现思路 下面是代码的实现思路&#xff1a; 导入必要的库和模块&#xff1a;首先&#xff0c;我们导入了Python的os、time库以及pygame库&#xff0c;还有植物大战僵尸游戏中用到的各个植物和僵尸的类。 初始化游戏和…

从零开始学AI绘画,万字Stable Diffusion终极教程(一)

【第1期】SD入门 2022年8月&#xff0c;一款叫Stable Diffusion的AI绘画软件开源发布&#xff0c;从此开启了AIGC在图像上的爆火发展时期 率先学会SD的人&#xff0c;已经挖掘出了越来越多AI绘画有趣的玩法 从开始的AI美女、线稿上色、真人漫改、头像壁纸 到后来的AI创意字、AI…

Android性能优化面试题汇总

Android的性能优化涉及多个方面,如启动优化、稳定性优化、内存优化、网络优化、电量优化、安全优化等方面。 一、稳定性优化 1.1 你们做了哪些稳定性方面的优化 随着项目的逐渐成熟,用户基数逐渐增多,DAU持续升高,我们遇到了很多稳定性方面的问题,对于我们技术同学遇到…

如何在 Ubuntu 16.04 上使用 WireGuard 创建点对点 VPN

简介 WireGuard 是一种现代、高性能的 VPN&#xff0c;旨在提供易于使用的同时又具有强大的安全性。WireGuard 专注于在网络接口上使用公钥认证加密来提供安全连接。这意味着&#xff0c;与大多数 VPN 不同&#xff0c;它不强制执行拓扑结构&#xff0c;因此可以通过操纵周围的…

条件依赖性的方法示例

5个条件判断一件事情是否发生&#xff0c;每个条件可能性只有2种&#xff08;发生或者不发生&#xff09;&#xff0c;计算每个条件对这件事情发生的影响力&#xff0c;条件之间有很强的依赖关系。 例一 如果条件之间有很强的依赖关系&#xff0c;那么简单地计算每个条件独立的…

[论文阅读] 测试时间自适应TTA

最初接触 CVPR2024 TEA: Test-time Energy Adaptation [B站]&#xff08;1:35:00-1:53:00&#xff09;https://www.bilibili.com/video/BV1wx4y1v7Jb/?spm_id_from333.788&vd_source145b0308ef7fee4449f12e1adb7b9de2 实现&#xff1a; 读取预训练好的模型参数设计需要更…