151.反转字符串里的单词
class Solution {
public:
void revese(string& s, int start, int end)
{
for(int i = start, j = end; i < j; i++, j--)
{
swap(s[i], s[j]);
}
}
string reverseWords(string s) {
// 根据题目条件,单词中会有前导空格和尾随空格,所以反转前应处理多余空格
// 去除首部空格
int fast = 0; int slow = 0; //定义快慢指针
while(fast < s.size() && s[fast] == ' ')
{
fast++;
}
// 去除中间多余空格
for(;fast < s.size(); fast++)
{
if(fast - 1 > 0 && s[fast- 1] == s[fast] && s[fast] == ' ')
{
continue; // 此处写的时候,没想到要用continue,还是代码功底不够,用了continue可以直接结束判断,执行下一次循环,不用再走else分支
}
else{
s[slow++] = s[fast]; // 不是空格,往前覆盖
}
}
// 去除尾部空格
s.resize(slow); // 注意slow最后是多加了1,如果没有空格,此时大小刚好合适
if(slow - 1 > 0 && s[slow - 1] == ' ') s.resize(slow - 1);
// 反转字符
revese(s, 0, s.size() - 1);
// 反转单词,以空格为分割点
int start = 0;
for(int i = 0; i <= s.size(); i++)
{
if(s[i] == ' ' || i == s.size()) // 遇到空格或到字符末尾
{
revese(s, start, i - 1);
start = i + 1;
}
}
return s;
}
};
关于去除字符串中多余的空格有下面更简洁的写法.
字符串的操作多离不开双指针,本题依然使用双指针
void removeExtraSpace(string& s)
{
int slow = 0;
for(int i = 0; i < s.size(); i++)
{
if(s[i] != ' ') // 不等于空格才进行操作,若是空格,直接结束判断,i++
{
// 对于单词之间要手动添加空格
if(slow != 0) s[slow++] = ' ';
while(i < s.size() && s[i] != ' ') // 此处一定要用while循环,只有用循环才能保证每次处理的是一整个单词,不然,每个字符之间会有一大推的空格,因为,在处理第一个单词的第二个字符时,slow就不再是零,如果没有while就会在每个字符间有一大堆的空格
{
s[slow++] = s[i++];
}
}
}
s.resize(slow);
}
28.实现strStr()
此题涉及到KMP算法。KMP算法用在寻找一个字符串是否在另一个字符串中出现
KMP算法需要构建前缀表。
构建前缀表的思路为:用两个指针指向前缀的最后一个字符和后缀的最后一个字符; 比较两者是否相等
相等在更新前缀表(next数组),不等则向前回溯。
KMP算法实际处理需借助前缀表。
待前缀表构建完成后,即按照前缀表逐字符匹配即可,相同则同时后移,不同则按照前缀表回溯
// 构建前缀表
void getNext(int* next, string& s)
{
int j = 0;
next[0] = j;
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 - j + 1);
}
}
return -1;
}
459.重复的子字符串
bool repeatedSubstringPattern(string s) {
// 如何借助前缀表判断是否有最小重复字串
// 如果 next[len - 1] != -1; 就说明有最大公共前后缀
// len - next[len - 1] 为减去最长公共前后缀的字符串长度
// len % (len - next[len - 1]) == 0 成立, 则说明有重复子串, 且子串长度就是len - next[len - 1]
// 自己实现KMP算法降低复杂度
if(s.size() == 0) return false;
int next[s.size()];
int len = s.size();
getNext(next,s);
if(next[len - 1] != 0 && len % (len - next[len - 1]) == 0) return true;
return false;
}
void getNext(int* next, string& s)
{
int j = 0;
next[0] = j;
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;
}
}