151.翻转字符串里的单词
leetcode题目链接
如果不使用辅助空间原地操作的话,算法会比较复杂一些。
分3步走:
- 删除额外的空格
- 翻转整个字符串
- 翻转每个单词
去除空格的操作和27. 移除元素是一样的思路,使用双指针将需要的元素挪到左指针,但是需要手动添加空格。我的逻辑是遇到非空格,除非是第一个单词,都手动添加一个空格,然后挪动一整个单词。在我的代码中,挪动完一个完整单词后,右指针会向后移动两个,不过这个并不影响结果。
class Solution {
public:
void reverse(string& s, int start, int end) {
int left = start, right = end;
while (left < right)
swap(s[left++], s[right--]);
}
void removeSpace(string& s) {
int left = 0;
for (int right = 0; right < s.size(); right++) {
if (s[right] != ' ') {
if (left != 0)
s[left++] = ' ';
while (right < s.size() && s[right] != ' ')
s[left++] = s[right++];
}
}
s.resize(left);
}
string reverseWords(string s) {
removeSpace(s);
reverse(s, 0, s.size() - 1);
int left = 0, right = 0;
while (left < s.size()) {
while (s[right] != ' ' && right < s.size())
right++;
reverse(s, left, right - 1);
right++;
left = right;
}
return s;
}
};
55. 右旋字符串
- 将字符串整体翻转,这样后n位就到前面来了
- 然后将前n位和余下的局部翻转。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
int n;
string s;
cin >> n >> s;
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
cout << s << endl;
}
28. 实现 strStr()
这一题就是要匹配字符串,暴力解法是两层for循环,时间复杂度是
O
(
n
∗
m
)
O(n*m)
O(n∗m)。
KMP算法对此进行了优化,当模式串与字符串出现冲突时,模式串不必回退到最开始,而是根据前缀表选择回退的下标,时间复杂度为
O
(
n
+
m
)
O(n+m)
O(n+m)。
class Solution {
public:
void contructNext(vector<int>& next, string needle) {
int j = 0;
next[j] = j;
for (int i = 1; i < needle.size(); ++i) {
while (needle[j] != needle[i] && j > 0)
j = next[j - 1];
if (needle[j] == needle[i])
j++;
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0)
return 0;
vector<int> next(needle.size());
contructNext(next, needle);
for (int i = 0, j = 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;
}
};
459.重复的子字符串
移动匹配
拼接一个s+s的新字符串,去除首尾,判断是否有s子串。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string t = s + s;
t = t.substr(1, t.size() - 2);
if (t.find(s) != std::string::npos)
return true;
else
return false;
}
};
KMP算法
字符串的最长相等前后缀所余下的是最小子串。
class Solution {
public:
void constructNext(vector<int>& next, string s) {
int j = 0;
next[j] = j;
for (int i = 1; i < s.size(); ++i) {
while (s[j] != s[i] && j > 0)
j = next[j - 1];
if (s[j] == s[i])
++j;
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
if (s.size() == 0)
return true;
vector<int> next(s.size());
constructNext(next, s);
int len = s.size();
if (len % (len - next[len - 1]) == 0 && next[len - 1])
return true;
else
return false;
}
};