今日练习内容:KMP算法
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"
方法一
直接进行字符串截取,然后拼接在一块就行
参考代码
略…
方法二
我们再次成为大佬,提高下难度:不能申请额外空间,只能在本串上操作
做法:局部+整体反转
- 反转区间为前n的子串
- 反转区间为n到末尾的子串
- 反转整个字符串
参考代码
string reverseLeftWords(string s, int n) {
reverse(s.begin(),s.begin()+n);
reverse(s.begin+n,s.end());
reverse(s.begin(),s.end());
return s;
}
28. 实现 strStr()
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入:haystack = "hello", needle = "ll"
输出:2
示例 2:
输入:haystack = "aaaaa", needle = "bba"
输出:-1
示例 3:
输入:haystack = "", needle = ""
输出:0
思路分析
纯正的KMP算法,不懂的可以看我这篇博客
参考代码
//获取next数组
void getNext(int &next,string &s){
int j = 0;
next[0] = 0;
for(int i = 1; i < s.size();i++){
while(j>0&&s[i]!=s[j]){
j = next[j-1];
}
if(s[i]==s[j]){
j++;
}
next[i] = j;//初始化next数组.
}
}
int strStr(string haystack, string needle) {
if(needle.size()==0){
return 0;
}
int next[needle.size];
getNext(next,needle);
int j = 0;
for(int i = 0;i < haystack.size();i++){
while(j>0 && haystack[i] != needle[j]){
j = next[j-1];//不相等则跳转到公共前缀的后一个字符处.
}
if(haystack[i]==needle[j]){//如果相等,则i,j进行后移动
j++;
}
if(j==needle.size()){
return (i-needle.size()+1);//返回起始的坐标
}
}
return -1;
}
459. 重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 “ab” 重复两次构成。
示例 2:
输入: "aba"
输出: False
示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串 “abcabc” 重复两次构成。)
思路分析
KMP算法的经典使用 外加一点小技巧
假设数组长度为len,如果len % (len - next[len - 1]) == 0 ,则说明
数组长度该字符串有重复的子字符串.
为什么呢?
数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
我们看一下Next数组就很清楚了,如下:
分析:在第一个周期内next[x]=0,当走出第一个周期后next[i]>0,所以如果该字符串可以由某一个子串组成,那么len - next[len - 1] 一定会被len整除的.
参考代码
void getNext(int next*,string &s){
int j = 0;
next[0] = 0;
for(int i = 1;i < s.size();i++){
while(j>0&&s[j]!=s[i]){//如果 s[j]!=s[i],则j调至前一个next
j = next[j-1];
}
if(s[j]==s[i]){
j++;
}
next[i] = j;//next数组进行更新
}
}
bool repeatedSubstringPattern(string s) {
if(s.size()==0){
return false;
}
int len = s.size();
int next[len];
getNext(next,s);
if(next[len-1]>0&& len %(len - next[len-1])==0){
return true;
}else{
return false;
}
}