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;
}
};
同上。