目录
- 一、反转字符串
- 二、反转字符串 II
- 三、替换空格
- 四、反转字符串中的单词
- 五、左旋转字符串
- 六、找出字符串中第一个匹配项的下标(KMP算法实现)
- 七、重复的子字符串
一、反转字符串
Leetcode 344
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0; i < s.size() / 2; i ++ )
swap(s[i], s[s.size() - 1 - i]);
}
};
二、反转字符串 II
Leetcode 541
使用库函数 reverse()
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
if (i + k <= s.size())
reverse(s.begin() + i, s.begin() + i + k);
else reverse(s.begin() + i, s.end());
}
return s;
}
};
三、替换空格
剑指 Offer 05
为了将时间复杂度做到 O ( n ) O(n) O(n),空间复杂度做到 O ( 1 ) O(1) O(1),可以先统计字符串中空格的个数,然后将字符串长度扩充到替换后的字符串的长度。接下来,采用双指针从后往前遍历, i i i 指向新长度的末尾, j j j 指向旧长度的末尾,遇到空格就替换掉。
class Solution {
public:
string replaceSpace(string s) {
int cnt = 0, len_old = s.size();
for (char c: s) // 统计空格个数
if (c == ' ') cnt ++ ;
s.resize(len_old + cnt * 2);
int len_new = s.size();
for (int i = len_new - 1, j = len_old - 1; j < i; i -- , j -- )
if (s[j] != ' ') s[i] = s[j];
else {
s[i] = '0', s[i - 1] = '2', s[i - 2] = '%';
i -= 2;
}
return s;
}
};
四、反转字符串中的单词
Leetcode 151
- 先去掉多余空格(快慢指针)
- 翻转整个字符串
- 翻转每个单词
class Solution {
public:
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i ++ , j -- )
swap(s[i], s[j]);
}
void removeExtraSpace(string& s) {
int slow = 0;
for (int i = 0; i < s.size(); i ++ )
if (s[i] != ' ') {
if (slow != 0) s[slow ++ ] = ' '; // 给单词之间添加空格
while (i < s.size() && s[i] != ' ') s[slow ++ ] = s[i ++ ]; // 补充完整单词
}
s.resize(slow);
}
string reverseWords(string s) {
removeExtraSpace(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for (int i = 0; i <= s.size(); i ++ )
if (i == s.size() || s[i] == ' ') {
reverse(s, start, i - 1);
start = i + 1;
}
return s;
}
};
五、左旋转字符串
剑指 Offer 58 -Ⅱ
class Solution {
public:
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;
}
};
六、找出字符串中第一个匹配项的下标(KMP算法实现)
Leetcode 28
详细 KMP 算法解释见参考文章
看文章时应该注意几点:
- 前后缀数组的含义,注意理解图中这句话
- next 数组与前后缀数组的联系
class Solution {
public:
void getNext(int *next, const string& s) {
next[0] = 0;
for (int i = 1, j = 0; i < s.size(); i ++ ) {
while (j && s[i] != s[j]) j = next[j - 1];
if (s[i] == s[j]) j ++ ;
next[i] = j;
}
}
int strStr(string s, string t) {
int next[t.size()];
getNext(next, t);
for (int i = 0, j = 0; i < s.size(); i ++ ) {
while (j && s[i] != t[j]) j = next[j - 1];
if (s[i] == t[j]) j ++ ;
if (j == t.size()) return i - t.size() + 1;
}
return -1;
}
};
七、重复的子字符串
Leetcode 459
解题关键:在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串
参考题解
class Solution {
public:
void getNext(int* next, const string& s) {
next[0] = 0;
for (int i = 1, j = 0; i < s.size(); i ++ ) {
while (j && s[i] != s[j]) j = next[j - 1];
if (s[i] == s[j]) j ++ ;
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
int next[s.size()];
getNext(next, s);
int len = s.size();
if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0)
return true;
return false;
}
};