今天學習了字串的第二部分。
- 翻轉字串裡的單詞,先整體翻轉,再區域性翻轉。注意移除空格和前頭陣列中移除元素類似。
- 右旋轉,也是先整體再區域性翻轉。
4. 翻轉字串裡的單詞
題目:給定一個字串,逐個翻轉字串中的每個單詞。
示例 1:
輸入: "the sky is blue"
輸出: "blue is sky the"
示例 2:
輸入: " hello world! "
輸出: "world! hello"
解釋: 輸入字串可以在前面或者後面包含多餘的空格,但是反轉後的字元不能包括。
示例 3:
輸入: "a good example"
輸出: "example good a"
解釋: 如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。
若是無限制,split庫函式,分隔單詞,然後定義一個新的string字串,最後再把單詞倒序相加。但是限定只可以在原字串裡操作,所以解題思路如下:
- 移除多餘空格
- 將整個字串反轉
- 將每個單詞反轉
舉個例子,源字串為:"the sky is blue "
- 移除多餘空格 : "the sky is blue"
- 字串反轉:"eulb si yks eht"
- 單詞反轉:"blue is sky the"
a. 移除多餘空格
總之屬於移除元素,參考陣列中移除元素的題目,採用快慢指標。其中6-8行的while負責迴圈完一個單詞,fast指標碰到空格,就跳出while,到最外層的for中fast++,此時根據slow是不是0判斷新開始的單詞開頭需不需要加空格。
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); //slow的大小即為去除多餘空格後的大小。
}
b. 字串翻轉
// 反轉字串s中左閉右閉的區間[start, end]
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
c.整體程式碼
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); //slow的大小即為去除多餘空格後的大小。
}
string reverseWords(string s) {
removeExtraSpaces(s); //去除多餘空格,保證單詞之間之只有一個空格,且字串首尾沒空格。
reverse(s, 0, s.size() - 1);
int start = 0; //removeExtraSpaces後保證第一個單詞的開始下標一定是0。
for (int i = 0; i <= s.size(); ++i) {
if (i == s.size() || s[i] == ' ') { //到達空格或者串尾,說明一個單詞結束。進行翻轉。
reverse(s, start, i - 1); //翻轉,注意是左閉右閉 []的翻轉。
start = i + 1; //更新下一個單詞的開始下標start
}
}
return s;
}
};
- 翻轉單詞,注意這個思想,整體翻轉+區域性反轉
- 移除多餘空格=移除元素,使用雙指標,只是注意對單詞前加一個空格的處理方式
5. 右旋轉字元
題目:字串的右旋轉操作是把字串尾部的若干個字元轉移到字串的前面。給定一個字串 s 和一個正整數 k,請編寫一個函式,將字串中的後面 k 個字元移到字串的前面,實現字串的右旋轉操作。
例如,對於輸入字串 "abcdefg"
和整數 2,函式應該將其轉換為 "fgabcde"
。
類比上一題,可以想到使用多次翻轉:
- 整體倒敘,把兩段子串順序顛倒
- 兩個段子串裡的的字元在倒敘,負負得正。
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
int len = s.size(); //獲取長度
reverse(s.begin(), s.end()); // 整體反轉
reverse(s.begin(), s.begin() + n); // 先反轉前一段,長度n
reverse(s.begin() + n, s.end()); // 再反轉後一段
cout << s << endl;
}
字串總結
基本可以分為以下幾部分掌握:
1. 常用庫函式
std::string::length
/std::string::size
-
作用:返回字串的長度(字元數)。
-
用法:
std::string str = "Hello, World!"; std::cout << "Length: " << str.length() << std::endl; // Output: Length: 13
std::string::empty
-
作用:檢查字串是否為空。
-
用法:
std::string str = ""; if (str.empty()) { std::cout << "The string is empty." << std::endl; }
std::string::clear
-
作用:清空字串,使其變為空字串。
-
用法:
std::string str = "Hello, World!"; str.clear(); std::cout << "After clear: " << str << std::endl; // Output: After clear:
std::string::append
/std::string::operator+=
-
作用:在字串末尾追加字元或字串。
-
用法:
std::string str = "Hello"; str.append(", World!"); std::cout << str << std::endl; // Output: Hello, World! str += " How are you?"; std::cout << str << std::endl; // Output: Hello, World! How are you?
std::string::substr
-
作用:返回字串中指定位置的子字串。
-
用法:
std::string str = "Hello, World!"; std::string sub = str.substr(7, 5); // 從位置7開始,擷取5個字元 std::cout << "Substring: " << sub << std::endl; // Output: Substring: World
std::string::find
-
作用:在字串中查詢子字串或字元,返回首次出現的位置索引。如果未找到,則返回
std::string::npos
。 -
用法:
std::string str = "Hello, World!"; size_t pos = str.find("World"); if (pos != std::string::npos) { std::cout << "'World' found at position: " << pos << std::endl; // Output: 'World' found at position: 7 }
std::string::replace
-
作用:用新的子字串替換字串中的部分內容。
-
用法:
std::string str = "Hello, World!"; str.replace(7, 5, "C++"); // 從位置7開始,替換5個字元為 "C++" std::cout << "After replace: " << str << std::endl; // Output: After replace: Hello, C++!
std::string::compare
-
作用:比較兩個字串的大小。
-
用法:
std::string str1 = "Apple"; std::string str2 = "Banana"; int result = str1.compare(str2); if (result < 0) { std::cout << "str1 is less than str2" << std::endl; } else if (result > 0) { std::cout << "str1 is greater than str2" << std::endl; } else { std::cout << "str1 is equal to str2" << std::endl; }
std::string::erase
-
作用:刪除字串中的部分內容。
-
用法:
std::string str = "Hello, World!"; str.erase(5, 7); // 從位置5開始,刪除7個字元 std::cout << "After erase: " << str << std::endl; // Output: After erase: Hello!
std::string::insert
-
作用:在字串的指定位置插入子字串。
-
用法:
std::string str = "Hello!"; str.insert(5, ", World"); // 在位置5插入 ", World" std::cout << "After insert: " << str << std::endl; // Output: After insert: Hello, World!
std::string::c_str
-
作用:返回一個指向 C 風格字串的指標(
const char*
)。 -
用法:
std::string str = "Hello, World!"; const char* cstr = str.c_str(); std::cout << "C-style string: " << cstr << std::endl; // Output: C-style string: Hello, World!
std::string::at
-
作用:返回字串中指定位置的字元,並進行邊界檢查。
-
用法:
std::string str = "Hello, World!"; char ch = str.at(1); // 獲取位置1處的字元 std::cout << "Character at index 1: " << ch << std::endl; // Output: Character at index 1: e
std::string::resize
-
作用:調整字串的大小,可以增加或減少長度。
-
用法:
std::string str = "Hello, World!"; str.resize(5); std::cout << "After resize: " << str << std::endl; // Output: After resize: Hello str.resize(10, '!'); std::cout << "After resize with fill: " << str << std::endl; // Output: After resize with fill: Hello!!!!!
std::string::push_back
/std::string::pop_back
-
作用:在字串末尾新增或刪除一個字元。
-
用法:
std::string str = "Hello"; str.push_back('!'); std::cout << "After push_back: " << str << std::endl; // Output: After push_back: Hello! str.pop_back(); std::cout << "After pop_back: " << str << std::endl; // Output: After pop_back: Hello
2. 雙指標解決問題
移除元素、反轉連結串列/字串、替換元素,這三樣都需要雙指標。
3. 翻轉問題
一段一段有規律的精細翻轉,考慮再for迴圈上做文章;一般的翻轉考慮區域性+整體的結合。
4. KMP經典演算法
需要熟練掌握。
今日古詩
唐多令·蘆葉滿汀洲
蘆葉滿汀洲,寒沙帶淺流。二十年重過南樓。柳下系船猶未穩,能幾日,又中秋。
黃鶴斷磯頭,故人今在否?舊江山渾是新愁。欲買桂花同載酒,終不似,少年遊。
《唐多令·蘆葉滿汀洲》是一首登臨名作,詞人借重過武昌南樓之機,感慨時事,抒寫昔是今非和懷才不遇的思想感情。詞的上闋抒發對時光流逝、物是人非的世道滄桑的強烈感受;下闋以疏俊之筆抒寫故友凋零、山河破碎、好夢不再的今昔感概。全詞懷舊撫今,情調哀傷,其詞意悽愴清越,委婉含蓄,耐人尋味。