字元產part02

YueHuai發表於2024-08-09

今天學習了字串的第二部分。

  1. 翻轉字串裡的單詞,先整體翻轉,再區域性翻轉。注意移除空格和前頭陣列中移除元素類似。
  2. 右旋轉,也是先整體再區域性翻轉。

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;
    }
};
  1. 翻轉單詞,注意這個思想,整體翻轉+區域性反轉
  2. 移除多餘空格=移除元素,使用雙指標,只是注意對單詞前加一個空格的處理方式

5. 右旋轉字元

題目:字串的右旋轉操作是把字串尾部的若干個字元轉移到字串的前面。給定一個字串 s 和一個正整數 k,請編寫一個函式,將字串中的後面 k 個字元移到字串的前面,實現字串的右旋轉操作。

例如,對於輸入字串 "abcdefg" 和整數 2,函式應該將其轉換為 "fgabcde"


類比上一題,可以想到使用多次翻轉:

  1. 整體倒敘,把兩段子串順序顛倒
  2. 兩個段子串裡的的字元在倒敘,負負得正
#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. 常用庫函式

  1. std::string::length / std::string::size
  • 作用:返回字串的長度(字元數)。

  • 用法

    std::string str = "Hello, World!";
    std::cout << "Length: " << str.length() << std::endl; // Output: Length: 13
    
  1. std::string::empty
  • 作用:檢查字串是否為空。

  • 用法

    std::string str = "";
    if (str.empty()) {
        std::cout << "The string is empty." << std::endl;
    }
    
  1. std::string::clear
  • 作用:清空字串,使其變為空字串。

  • 用法

    std::string str = "Hello, World!";
    str.clear();
    std::cout << "After clear: " << str << std::endl; // Output: After clear:
    
  1. 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?
    
  1. 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
    
  1. 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
    }
    
  1. 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++!
    
  1. 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;
    }
    
  1. 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!
    
  1. 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!
    
  1. 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!
    
  1. 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
    
  1. 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!!!!!
    
  1. 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經典演算法

需要熟練掌握。

今日古詩

唐多令·蘆葉滿汀洲

蘆葉滿汀洲,寒沙帶淺流。二十年重過南樓。柳下系船猶未穩,能幾日,又中秋。
黃鶴斷磯頭,故人今在否?舊江山渾是新愁。欲買桂花同載酒,終不似,少年遊。

《唐多令·蘆葉滿汀洲》是一首登臨名作,詞人借重過武昌南樓之機,感慨時事,抒寫昔是今非和懷才不遇的思想感情。詞的上闋抒發對時光流逝、物是人非的世道滄桑的強烈感受;下闋以疏俊之筆抒寫故友凋零、山河破碎、好夢不再的今昔感概。全詞懷舊撫今,情調哀傷,其詞意悽愴清越,委婉含蓄,耐人尋味。

相關文章