151.翻转字符串里的单词
题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/description/
暴力removeExtraSpaces:
void removeExtraSpaces(string& s) {
for (int i = s.size() - 1; i > 0; i--) {
if (s[i] == ' ' && s[i] == s[i - 1]) {
s.erase(s.begin() + i);
}
}
if (s.size() > 0 && s[0] == ' ') {
s.erase(s.begin());
}
if (s.size() > 0 && s[s.size() - 1] == ' ') {
s.erase(s.begin() + s.size() - 1);
}
}
遇到多余空格就erase一下,时间复杂度比较高。
removeExtraSpaces版本一:
void removeExtraSpaces(string& s) {
int slowIndex = 0, fastIndex = 0;
while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
fastIndex++;
}
for (; fastIndex < s.size(); fastIndex++) {
if (fastIndex > 1 && s[fastIndex] == s[fastIndex - 1] &&
s[fastIndex] == ' ') {
continue;
} else {
s[slowIndex++] = s[fastIndex];
}
}
if (slowIndex > 1 && s[slowIndex - 1] == ' ') {
s.resize(slowIndex - 1);
} else {
s.resize(slowIndex);
}
}
一般的思考过程,就是先移除字符串前的空格,再移除中间的,再移除后面部分。
removeExtraSpaces版本二:
void removeExtraSpaces(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);
}
比版本一精简,遇到非空格就处理。
完整代码:
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 removeExtraSpaces(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) {
removeExtraSpaces(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for (int i = 0; i <= s.size(); ++i) {
if (s[i] == ' ' || i == s.size()) {
reverse(s, start, i - 1);
start = i + 1;
}
}
return s;
}
};
比较综合的一道题目。
卡码网:55.右旋转字符串
题目链接:https://kamacoder.com/problempage.php?pid=1065
我的代码:
#include <iostream>
using namespace std;
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
int main() {
string s;
int n;
cin >> n >> s;
reverse(s, 0, s.size() - 1);
reverse(s, 0, n - 1);
reverse(s, n, s.size() - 1);
cout << s << endl;
return 0;
}
通过三次倒序,一次整体倒序,两次分段倒序,得到右旋子串。
28.实现 strStr()
题目链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
前缀表(不减一)C++实现:
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = j;
for (int i = 1; i < s.size(); i++) {
while (j > 0 && s[j] != s[i]) {
j = next[j - 1];
}
if (s[j] == s[i]) {
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
vector<int> next(needle.size());
getNext(&next[0], needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
while (j > 0 && needle[j] != haystack[i]) {
j = next[j - 1];
}
if (needle[j] == haystack[i]) {
j++;
}
if (j == needle.size()) {
return i - j + 1;
}
}
return -1;
}
};
直接用前缀表作为next数组的值,KMP算法的典型例题。
前缀表统一减一C++实现:
class Solution {
public:
void getNext(int* next, const string& s) {
int j = -1;
next[0] = j;
for (int i = 1; i < s.size(); i++) {
while (j >= 0 && s[j + 1] != s[i]) {
j = next[j];
}
if (s[j + 1] == s[i]) {
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
vector<int> next(needle.size());
getNext(&next[0], needle);
int j = -1;
for (int i = 0; i < haystack.size(); i++) {
while (j >= 0 && needle[j + 1] != haystack[i]) {
j = next[j];
}
if (needle[j + 1] == haystack[i]) {
j++;
}
if (j == needle.size() - 1) {
return i - j;
}
}
return -1;
}
};
前缀表减一作为next数组的值,KMP算法的典型例题。
459.重复的子字符串
题目链接:https://leetcode.cn/problems/repeated-substring-pattern/description/
移动匹配法:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string t = s + s;
t.erase(t.begin());
t.erase(t.end() - 1);
if (t.find(s) != std::string::npos)
return true;
return false;
}
};
判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成,要注意刨除 s + s 的首字符和尾字符,这样避免在s+s中搜索出原来的s。
KMP(前缀表统一减一):
class Solution {
public:
void getNext(int* next, const string& s) {
int j = -1;
next[0] = j;
for (int i = 1; i < s.size(); i++) {
while (j >= 0 && s[j + 1] != s[i]) {
j = next[j];
}
if (s[j + 1] == s[i]) {
j++;
}
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
vector<int> next(s.size());
getNext(&next[0], s);
int len = s.size();
if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
return true;
}
return false;
}
};
如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀,如果len % (len - (next[len - 1] + 1)) == 0 ,则说明数组的长度正好可以被 (数组长度-最长相等前后缀的长度) 整除 ,说明该字符串有重复的子字符串。
KMP(前缀表不减一):
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = j;
for (int i = 1; i < s.size(); i++) {
while (j > 0 && s[j] != s[i]) {
j = next[j - 1];
}
if (s[j] == s[i]) {
j++;
}
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
vector<int> next(s.size());
getNext(&next[0], s);
int len = s.size();
if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0) {
return true;
}
return false;
}
};
同上。
标签:151,string,int,随想录,next,++,&&,字符串,size From: https://www.cnblogs.com/kurumaruq/p/18350887