P28 实现strStr()
题目链接:P28 实现strStr()
题目描述:
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
1 <= haystack.length, needle.length <= 104
haystack
和needle
仅由小写英文字符组成
思路:
自己想不出来,看解析说是使用kmp算法
代码:
class Solution {
public:
void getNext(int* next,const 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;
}
}
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]){
j++;
}
if(j ==needle.size()){
return (i -needle.size() +1);
}
}
return -1;
}
};
P459 重复的子字符串
题目链接:P459 重复的子字符串
题目描述:
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length <= 104
s
由小写英文字母组成
思路:
1.暴力解法:编写两个for循环,第一个for循环负责不断读取s字符串里面的字符并存进ss中,当读到 s.size() % s.size() ==0 的时候就进行一次判断,判断n个ss是否可以构成s,如果可以就返回ture,这个方法还可以得到匹配字符串。
代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string ss;
bool result = false;
for(int i =0;i<s.size()/2;i++){
ss = ss + s[i];
if(s.size()% ss.size() ==0){
string newS;
for(int j =1;j<=s.size()/ss.size();j++){
newS=newS +ss;
}
if(newS == s){
cout<<ss<<endl;
result = true;
break;
}
}
}
return result;
}
};
2.如果一个字符串可以由最小字串构成的话,那个在字符串s+s 中必然会会存在一个s,假设 最小字串为minstring , 那么我们可以设 s = n *minstring ,那么 s+s 则具有 2n个minstring,所以其中必然能够找到一个字符串s。使用这个方法有一个注意事项就是需要对 s+s进行一个掐头去尾的操作,防止出现的是原来的两个s。
代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string ss = s + s;
ss.erase(ss.begin());
ss.erase(ss.end()-1);
//find 返回的是字符串的索引
if(ss.find(s) != string::npos){
return true;
}else{
return false;
}
}
};
3.能够通过的解法,时间复杂度也是O(n^2)
卡哥在讲kmp的时候说的当一个字符串由重复子串组成的,最长相等前后缀不包含的子串就是最小重复子串。
那么我们就可以定义一个字符串before与after,表示前缀和后缀,然后不断地枚举,直到找到第一个相等的前后缀,就是最小重复子串。
代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int count = -1;
for(int i = 0;i<s.size()/2;i++){
string before = string(s.begin()+i+1,s.end());
string after = string(s.begin(),s.end()-i-1);
if(before == after){
count = i;
break;
}
}
if(count ==0){
return true;
}else if(count != -1 && s.size() % (count +1 ) ==0){
return true;
}else{
return false;
}
}
};
4.kmp算法
class Solution {
public:
void getNext (int* next, const string& s){
next[0] = -1;
int j = -1;
for(int i = 1;i < s.size(); i++){
while(j >= 0 && s[i] != s[j + 1]) {
j = next[j];
}
if(s[i] == s[j + 1]) {
j++;
}
next[i] = j;
}
}
bool repeatedSubstringPattern (string s) {
if (s.size() == 0) {
return false;
}
int next[s.size()];
getNext(next, s);
int len = s.size();
if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
return true;
}
return false;
}
};
没弄懂,明天再看。