参考博客:
KMP算法到底在干什么:https://blog.csdn.net/kornberg_fresnel/article/details/78002188
KMP算法最浅显理解——一看就明白:https://blog.csdn.net/starstar1992/article/details/54913261
KMP入门级别算法详解--终于解决了(next数组详解):
https://blog.csdn.net/lee18254290736/article/details/77278769
字符串匹配的KMP算法:
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
Boyer–Moore算法
字符串专题
1.1 字符串的旋转
题目描述:
将前部的字符子串整体移到字符串的尾部 (abcdef->defabc)
算法思想:
1、采用暴力的解法,每次移动一个字符到末尾,那么一次操作需要移动n个字符(n为字符串长度),若子串长度设为m,共需进行m*n次移位操作。则时间复杂度为O(mn),空间复杂度为O(1)
void LeftShiftOne(char *s, int n){
char first_word = s[0];
for(int i = 1; i < n; i++ ){
s[i-1] = s[i];
}
s[n-1] = first_word;
}
void LeftRotateString(char *s, int m){
while(m--){
LeftShiftOne(s, 10);
}
}
2、新时代优秀青年肯定不能使用这种简单低效的解法。于是考虑先将需要移动的子串和剩余子串分别进行反转,再进行整体反转(三步反转法:1、分块 2、子串反转 3、整体反转)
void ReverseString(char*s, int from, int to){//字符串反转算法,切记不要将字符串拆开分别存在数组中,直接用字符指针操作字符串,方便快捷
char temp;
while(from < to){
temp = s[from];
s[from++] = s[to];
s[to--] = temp;
}
}
int main(){
char text[] = "worldhello";
ReverseString(text, 0, 4); //三次反转操作
ReverseString(text, 5, 9);
ReverseString(text, 0, 9);
printf("%s", text);
return 0;
}
1.1.3 单词翻转
题目描述:
翻转句子中单词的顺序,要求单词内字符的顺序不变。例:输入“I am a student.”输出“student. a am I”
算法思想:
做字符串反转,先考虑子串反转,再考虑整个字符串反转。 反转函数要牢记。
void ReverseString(char*s, int from, int to){
char temp;
while(from < to){
temp = s[from];
s[from++] = s[to];
s[to--] = temp;
}
}
int main(){
char text[] = "I am a student.";
int from(0), to;
for(int i = 0; i < 15; i++){
if(text[i] == ' '){
to = i-1;
ReverseString(text, from, to);
from = i+1;
}
}
ReverseString(text, 0, 14);
printf("%s", text);
return 0;
}
1.2 字符串的包含
题目描述:
给定长串a和短串b,请快速判断短串b中的字符是否都在长串a中
算法思想:
1、排序后轮询。先对a、b字符串进行排序,依次将b中的每个字符和a中的每个字符进行比较,如果不同,输出false,否则输出true
两次排序分别需要O(mlogm)+O(nlogn),线性扫描需要O(m+n)
bool StringContain(string &a, string &b){
sort(a.begin(), a.end());
sort(b.begin(), b.end());
int i,j = 0;
for(; j < b.length(); ){
if(b[j] == a[i])
j++;
else if(i < a.length()){
i++;
}
else
return false;
}
return true;
}
2、素数相乘。素数有一个特别的性质:只能被1和自身整除。用26个素数代表26个字母,进行a字符串的素数相乘操作,再将b字符串对应的素数作为除数,如果相除有余数,输出false,否则输出ture
bool StringContain(string &a, string &b){
const int p[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
int count_a= 1, temp;
for(int i =0; i < a.length(); i++)
count_a *= p[a[i]-'A'];
for(int i = 0; i < b.length(); i++)
if(count_a % p[b[i]-'A'])
return false;
return true;
}
但是,素数相除极易导致整数溢出(超过long long),所以该方法看似可行,实则不可行
3、