字符串的小伙伴
Posted summer20020929
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串的小伙伴相关的知识,希望对你有一定的参考价值。
字符串小朋友结交了很多好朋友,他们大多都很乐于助人,帮助字符串解决他的问题
一.字符串哈希
字符串渴望和整数交好朋友,哈希是一个连接字符串和整数之间的媒介,他可以把字符串和整数相互匹配。哈希是多少?当然这个是要做题的人自己来设置的。
求一个字符串前缀哈希的公式是:hash【i】=(1ll *hash【i-1】*p+idx(s【i】))%mod;
其中p自己设为一个六位或八位的素数,mod取1e9+7或者+9,idx(s[i])=s[i]-‘a‘
现在咱来讲一下怎么求一个子串的hash,公式是:hash[L...R]=((hash[R]-hash[L-1]*(p的R-L+1次方))%mod+mod)%mod
常用的几个字符串哈希法:1 unsigned long long hash[N] hash[i]=hash[i-1]*自动取模
2 单哈希
3 双哈希,用pair<hash1,hash2>表示一个字符串mod1=1e9+7,mod2=1e9+9
哈希的应用:
1 求s1是不是s2的子串,且在s2中出现了几次
2 求s1和s2的最大公共子串
3 求一个字符串里的最长回文字符串
4 一系列操作后求字典序最小的表示法
哈希代码如下:
//用单hash表示字符串前缀 //并且判断s1在s2中出现了几次 void hashbuild(int n1,int n2){ for(int i=1;i<=n1;i++){ hash1[i]=(1ll*hash1[i-1]*p+s1[i]=‘a‘)%mod; } for(int i=1;i<=n2;i++){ hash2[i]=(1ll*hash2[i-1]*p+s2[i]-‘a‘)%mod; } for(int i=1;i<=n2;i++){ fp[i]=pow(p,i); } for(int i=n1;i<=n2;i++){ if((hash2[i]-1ll*hash2[i-n1]*fp[n1]%mod+mod)%mod==hash[n1])ans++; } } hash 1
//用单hash表示字符串前缀 //并且判断s1在s2中出现了几次 void hashbuild(int n1,int n2){ for(int i=1;i<=n1;i++){ hash1[i]=(1ll*hash1[i-1]*p+s1[i]=‘a‘)%mod; } for(int i=1;i<=n2;i++){ hash2[i]=(1ll*hash2[i-1]*p+s2[i]-‘a‘)%mod; } for(int i=1;i<=n2;i++){ fp[i]=pow(p,i); } for(int i=n1;i<=n2;i++){ if((hash2[i]-1ll*hash2[i-n1]*fp[i]%mod+mod)%mod==hash[n1])ans++
二.KMP算法
用来看s1是不是s2的子串
next是前缀后缀相同部分最大值
next:AAA
位置 0 1 2
j= 1 2 3
next -1 0 1
注意第i个位置看前i-1个,且不要算自己
next值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。
KMP算法
假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
- 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
- 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。
//优化过后的next 数组求法 void GetNextval(char* p, int next[]) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { //p[k]表示前缀,p[j]表示后缀 if (k == -1 || p[j] == p[k]) { ++j; ++k; //较之前next数组求法,改动在下面4行 if (p[j] != p[k]) next[j] = k; //之前只有这一行 else //因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]] next[j] = next[k]; } else { k = next[k]; } } }
返回值是s1在s2中出现的位置
int KmpSearch(char* s, char* p) { int i = 0; int j = 0; int sLen = strlen(s); int pLen = strlen(p); while (i < sLen && j < pLen) { //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++ if (j == -1 || s[i] == p[j]) { i++; j++; } else { //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j] //next[j]即为j所对应的next值 j = next[j]; } } if (j == pLen) return i - j+1; else return -1; }
以上是关于字符串的小伙伴的主要内容,如果未能解决你的问题,请参考以下文章