今天字符串的前两道还好,后两道直接跳过了。。感觉那个KMP算法太难了,我看了视频还是觉得云里雾里的。。
前两道题的思路都是整体反转+局部反转,我觉得这个套路很经典。
151.翻转字符串里的单词
这道题直接将所有字符串反转,然后删除多余的空格,最后将每一个单词反转即可,反转整个字符串和局部的单词可以使用reverse()函数,删除多余的空格还是用经典的双指针法来实现。
这是我的代码
class Solution {
public:
string reverseWords(string s) {
// 1. 先去除多余空格
int i, j;
i = 0;
j = 0;
while(j < s.size()){
if(s[j] != ' '){
if(i != 0){
s[i] = ' ';
i++;
}
while(j < s.size() && s[j] != ' '){
s[i] = s[j];
i++;
j++;
}
}
j++;
}
s.resize(i);
// 2. 反转字符串
for(i = 0, j = s.size() - 1; i < j; ){
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
// return s;
// 3.反转字符串中的单词
i = 0;
j = 0;
while(i < s.size()){
while(s[i] != ' ' && i < s.size()) //找到下一个空格的位置
i++;
reverse(s.begin() + j, s.begin() + i);
i++;
j = i;
}
return s;
}
};
卡码网:55.右旋转字符串
这个和上一题思路一样,我偷懒直接调用库函数了,很快就AC
这是我的代码
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
void my_rotate(string &s, int k){
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + k);
reverse(s.begin() + k, s.end());
}
int main(){
int k;
string s;
cin >> k;
cin >> s;
my_rotate(s, k);
cout << s << endl;
}
后面两道题居然是简单难度???!这两道题目的思路感觉都很难,看来还是要找时间把KMP算法啃一啃。。把那两道题弄明白以后我会更新这篇博客。我一定会回来的。
今天是8月23号,把KMP算法的流程弄懂了,但是我感觉还不够牢固,就只做了一题,还有一题留着明天做。
28. 实现 strStr()
这道题的难点在于两个:
1.如何构造next数组
2.有了next数组以后,应该如何去匹配。
首先构造next数组的方式是固定的,一般来说将其封装成一个函数会更加方便,至于构造next数组的具体实现流程,直接去代码随想录看讲解就可以。
但是代码随想录视频没有具体讲解你拿到next数组以后应该如何去匹配,简单来说就是用两个指针i和j,i指向haystack,j指向needle,使用一个循环,当i遍历完haystack中的所有字符后循环终止,在循环中则比较i和j指向的字符是否相等,若相等,则i和j都向后偏移一位,若不相等,则j跳转到next[j - 1]的位置,如果此时j已经为0,则j不再跳转,直接让i向后偏移一位。当找到匹配项时,此时j=needle.size(),直接return i - j即可,提前终止循环。
这是我的代码
class Solution {
public:
int strStr(string haystack, string needle) {
vector<int> next(needle.size());
getNext(needle, next);
int i, j;
for(i = 0, j = 0; i < haystack.size(); ){
if(haystack[i] == needle[j]){
j++;
i++;
if(j >= needle.size())
return i - j;
}
else{
if(j > 0)
j = next[j - 1];
else
i++;
}
}
return -1;
}
void getNext(string s, vector<int> &next){
/**************1.初始化**************/
//i为后缀末尾位置,j为前缀末尾位置
int i, j;
j = 0;
next[0] = 0;
for(i = 1; i < s.size(); i++){
/**************2.前后缀不相同**************/
while(j > 0 && s[i] != s[j])
j = next[j - 1];
/**************3.前后缀相同***************/
if(s[i] == s[j])
j++;
/**************4.更新next数组***************/
next[i] = j;
}
}
};
今天是8月24号,把剩下的一题也做了,感觉在做的时候对next数组的构造流程还是有些生疏。
这道题目就直接对输入的字符串s求next数组,next数组最后一个位置存放的数就代表着字符串s的最长相等前后缀的长度,如果这个字符串可以由某个子串构成的话,则子串的长度就是s.size() - next[s.size() - 1],如果求得的子串长度为0,则说明不能由某个子串构成,这个判断逻辑不能少!!!如果不为0,则用s.size()对子串长度求余,若结果为0则说明可以构成,否则不可以
这是我的代码。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
vector<int> next(s.size());
getNext(next, s);
//如果一个字符串可以由一个子串重复构成,则len(sub) == s.size() - next[s.size() - 1]
if(next[s.size() - 1] != 0 && s.size() % (s.size() - next[s.size() - 1]) == 0)
return true;
return false;
}
void getNext(vector<int> &next, string s){
//1.初始化
int i, j; //j指向前缀末尾,i指向后缀末尾
j = 0;
next[0] = 0;
for(i = 1; i < s.size(); i++){
//2.前后缀不相等
while(j > 0 && s[i] != s[j])
j = next[j - 1];
//3.前后缀相等
if(s[i] == s[j])
j++;
//4.更新next数组
next[i] = j;
}
}
};
这几道题终于刷完了,感觉KMP算法还是有点难,后面肯定得二刷。