《STL 六大組件之容器探秘:深入剖析 string》

目錄

  • 一、string 類簡介
  • 二、string 類的常用接口
    • 1. 構造函數(constructor function)
    • 2. 與容量相關的接口(capacity)
    • 3. 與迭代器有關的接口(iterator)
    • 4. 與元素訪問有關的接口(element access)
    • 5. 與內容修改有關的接口(modify)
    • 6. 與 string 對象操作有關的接口(operation)
    • 7. string 類的關系運算符重載接口
    • 8. string 類的輸入輸出
  • 三、與 string 類相關的精選習題
    • 1. 把字符串轉換成整數(atoi)
    • 2. 字符串相加
    • 3. 僅僅反轉字母
    • 4. 字符串中的第一個唯一字符
    • 5. 字符串最后一個單詞的長度
    • 6. 驗證回文串
    • 7. 反轉字符串Ⅱ
    • 8. 反轉字符串中的單詞Ⅲ
    • 9. 字符串相乘

一、string 類簡介

??string 是 C++ 標準庫中的一個類,該類專門用來管理字符串。相比于 C 語言中使用字符數組來管理字符串,string 類使用方便且更加強大。
??不同于 C 風格字符串,string

二、string 類的常用接口

??string 類一共有一百多個接口,而常用的接口也就二十來個。所以需要牢牢掌握這常用的二十來個結構,剩下的接口在需要的時候會查詢文檔即可。

1. 構造函數(constructor function)

??以下是 C++ 標準庫中 string 類的構造函數,上半部分是常用的構造函數,需要掌握且熟練運用;而下半部分不常用的構造函數只需了解即可。

(1)函數原型

// 構造函數// 常用的構造函數
string();  // 默認構造函數
string(const string& str);  // 復制構造函數
string(const char* str)  // 用 C 字符串 s 初始化
string(const char* s, size_t n);  // 用 C 字符串 s 的前 n 個字符初始化
string(size_t n, char c);  // 用 n 個字符 c 初始化// 不常用的構造函數
string (const string& str, size_t pos, size_t len = npos);  // 用 string 類對象 str 的下標為 pos 開始的長度為 len 的子串初始化
template <class InputIterator>  string  (InputIterator first, InputIterator last);  // 用迭代器[first, last)范圍內的字符串初始化

(2)使用演示

// string 構造函數使用演示
void test1()
{// 默認構造函數string str1;cout << "str1 = " << str1 << endl;// 使用 C 字符串初始化string str2("apple");cout << "str2 = " << str2 << endl;// 復制構造函數string str3(str2);cout << "str3 = " << str3 << endl;// 用 C 字符串的前 n 個字符初始化string str4("aaabbb", 3);cout << "str4 = " << str4 << endl;// 用 n 個字符 c 初始化string str5(5, 'e');cout << "str5 = " << str5 << endl;
}

(3)運行結果
在這里插入圖片描述

2. 與容量相關的接口(capacity)

??與 C 字符串相比 string 類的一個明顯的優勢在于它可以根據字符串的長度進行自動增容。而 C 字符串需要提前計算好字符串的長度而開辟相應大小的字符數組。

(1)函數原型

// 常用的與容量有關的接口
size_t size() const;  // 返回當前 string 類對象的長度(與其他 STL 組件保持一致)
size_t length() const;  // 返回當前 string 類對象的長度(未把 string 列為 STL 之前使用的成員函數)
void resize(size_t n);  // 把當前 string 對象的 size 修改至 n
void resize(size_t n, char c);  // 把當前 string 對象的 size 修改至 n,并把新增的字符全部設置為 c
size_t capacity() const;  // 返回當前 string 類對象的容量
void reserve(size_t n = 0);  // 把當前 string 類對象的容量修改為 n
bool empty() const;  // 判斷當前 string 類對象是否為空,若為空返回 true,否則返回 false// 不常用的與容量有關的接口
size_t max_size() const;  // 返回 string 類對象的最大容量(可以容納的最長字符數)
void clear();  // 把當前 string 類對象的內容清空,長度變為 0,容量不變
void shrink_to_fit();  // 請求字符串減小容量來適應 size 的大小

(2)使用演示

// string 類與容量有關的函數使用演示
void test2()
{string str1("C++");// 原 size 和 capacitycout << "Size: " << str1.size() << endl;cout << "Capacity: " << str1.size() << endl;cout << "Length: " << str1.length() << endl;// 修改 size 并指定字符str1.resize(5, 'a');cout << "\nstr1 = " << str1 << endl;cout << "Size: " << str1.size() << endl;cout << "Capacity: " << str1.size() << endl;// 修改 capacitystr1.reserve(18);cout << "\nstr1 = " << str1 << endl;cout << "Size: " << str1.size() << endl;cout << "Capacity: " << str1.size() << endl;// 清空并判斷當前 string 對象是否為空str1.clear();cout << "\nstr1 = " << str1 << endl;cout << "Size: " << str1.size() << endl;cout << "Capacity: " << str1.size() << endl;if (str1.empty())cout << "Current string is empty.\n";
}

(3)運行結果
在這里插入圖片描述

3. 與迭代器有關的接口(iterator)

??迭代器是所有 STL 容器都支持的一種訪問手段,迭代器的實質可以是指針也可以是其他自定義類型。支持迭代器也就支持范圍 for。

(1)函數原型

// 常用的迭代器接口
iterator begin();  // 返回普通 string 對象的開頭迭代器
iterator end();  // 返回普通 string 對象的尾后迭代器
const_iterator begin() const;  // 返回 const string 對象的開頭迭代器
const_iterator end() const;  // 返回 const string 對象的尾后迭代器
reverse_iterator rbegin();  // 返回普通 string 對象最后一個元素的迭代器
reverse_iterator rend();  // 返回普通 string 對象第一個元素前一個元素的迭代器
const_reverse_iterator rbegin() const;  // 返回 const string 對象最后一個元素的迭代器
const_reverse_iterator rend(); const  // 返回 const string 對象第一個元素前一個元素的迭代器// 還有幾個前綴 c 的不常用的迭代器接口,用來返回 const 類型的迭代器,也就等價于上述四個返回 const 迭代器的接口。感興趣的可以自己去查詢一下文檔
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

(2)使用演示
??對迭代器可以使用解引用操作符(*)獲得當前位置的元素。下面展示可以訪問 string 元素的幾種方法。

// string 類迭代器相關函數使用演示
// string 類迭代器相關函數使用演示
void test3()
{string str("Good night, everyone !");// 使用迭代器正序遍歷string::iterator it = str.begin();while (it != str.end()){cout << *it;++it;}cout << endl;// 使用迭代器逆序遍歷string::reverse_iterator rit = str.rbegin();while (rit != str.rend()){cout << *rit;++rit;}cout << endl;// 使用范圍 for 遍歷(編譯器在編譯階段會替換成迭代器)for (const auto& it : str)cout << it;cout << endl;// 普通 string 類對象可以使用 const 迭代器string::const_iterator cit = str.begin();// const string 類不可以使用普通迭代器const string str1("C++");//it = str1.begin();  // 報錯cit = str1.begin();  // 正確,const 對象只能使用 const 迭代器
}

(3)運行結果
在這里插入圖片描述

4. 與元素訪問有關的接口(element access)

??string 類通過使用下標運算符訪問其類對象的元素,當然還有其他幾個不常用的接口;

(1)函數原型

// 常用的訪問元素有關的接口
char& operator[](size_t pos);  // 返回普通 string 對象 pos 下標處的字符引用
const char& operator[](size_t pos) const;  // 返回 const string 對象 pos 下標出的字符引用// 不常用的訪問元素有關的接口
// at 接口與上面兩個函數的區別在于,at 檢查下標時會發出異常,而下標運算符使用斷言
char& at(size_t pos);
const char& at(size_t pos) const;
// 返回當前 string 對象的最后一個字符的引用
char& back();
const char& back() const;
// 返回當前 string 對象的第一個字符的引用
char& front();
const char& front() const;

(2)使用演示

// (4)string 類訪問元素相關的接口
void test4()
{string str("little fool");// 使用下標運算符訪問 str 的每個字符元素for (int i = 0; i < str.size(); ++i)cout << str[i];cout << endl;
}

(3)運行結果
在這里插入圖片描述

5. 與內容修改有關的接口(modify)

??string 類修改內容的接口有很多個,但最常用的是 += 操作符重載,該操作符重載既可以在末尾拼接字符串,也可以在末尾拼接單個字符。

(1)函數原型

// 常用的 string 修改內容的接口
string& operator+=(const string& str);  // 在當前 string對象末尾拼接一個 string 對象 str
string& operator+=(const char* s);  // 在當前 string 對象末尾拼接一個 C 風格字符串 s
string& operator+=(char c);  // 在當前 string 對象末尾拼接一個字符 c
void push_back(char c);  // 在當前 string 對象末尾拼接一個字符 c
string& append(const string& str);  // 在當前 string 對象末尾拼接一個 string 對象
string& append(const char* s);  // 在當前 string 對象末尾拼接一個 C 風格字符串
string& append(size_t n, char c);  // 在當前 string 對象末尾拼接 n 個字符 c
// insert() 接口有多個重載,需要的時候需要查閱相關文檔
string& insert(size_t pos, const string& str);  // 在當前 string 對象的下標 pos 處插入一個 string 對象 str
string& insert(size_t pos, const char& s);  // 在當前 string 對象的下標 pos 處插入一個 C 風格字符串
string& erase(size_t pos = 0, size_t len = npos);  // 刪除當前 string 對象從 pos 位置開始的長度為 len 的子串
iterator erase(iterator p);  // 刪除當前迭代器位置對應的字符,返回下一個字符的迭代器
void swap(string& str);  // 把當前 string 對象和 str 交換
void pop_back();  // 刪除當前 string 對象的最后一個字符// 不常用的 string 修改內容的接口
iterator erase(iterator first, iterator last);  // 刪除該迭代器區間的所有字符,返回 last 后一個位置的迭代器
// assign() 接口,給當前 string 對象重新賦值,但 string 類主要使用賦值運算符重載給 string 對象重新賦值
string& assign(const string& str);
string& assign(const char* s);
// replace() 接口,替換當前 string 對象的部分內容
string& replace(size_t pos, size_t len, const string& str);  // 從當前 string 對象的下標 pos 開始,使用 str 的前 len 個字符替換

(2)使用演示

// (5)string 類修改內容有關的接口
void test5()
{string str("Hello");// string 類的 += 操作符重載演示str += ' ';str += "world";string str1(" !");str += str1;cout << "str = " << str << endl;// 尾插和尾刪str.push_back('A');cout << "str = " << str << endl;str.pop_back();cout << "str = " << str << endl;// 在任意位置插入string str2("A");str2.insert(1, "apple");cout << "str2 = " << str2 << endl;int end = (int)str2.size();str2.insert(end, ".");cout << "str2 = " << str2 << endl;// 在任意位置刪除int len = (int)str2.size() - 1;str2.erase(1, len);cout << "str2 = " << str2 << endl;// 交換兩個 string 對象string str3("Java");string str4("python");cout << "str3 = " << str3 << endl;cout << "str4 = " << str4 << endl;str3.swap(str4);cout << "str3 = " << str3 << endl;cout << "str4 = " << str4 << endl;
}

(3)運行結果
在這里插入圖片描述

6. 與 string 對象操作有關的接口(operation)

??雖然 stirng 類對象不需要以空字符結尾,但是由于 C++ 兼容 C,所以其結尾依舊保留空字符,而使用 c_str() 接口,可以獲得其 C 風格字符串的形式,也就是字符指針(char*)。

(1)函數原型

// 常用的與 string 對象操作有關的接口
const char* c_str() const;  // 返回當前 string 對象首字符的地址
size_t find(const string& str, size_t pos = 0) const;  // 在當前 string 對象的 pos 位置開始,尋找 stirng 對象 str 首次出現的位置
size_t find(const char* s, size_t pos = 0) const;  // 在當前 string 對象 pos 位置開始,尋找 C 風格字符串 s 首次出現的位置
size_t find(char c, size_t pos = 0) const;  // 在當前 string 對象 pos 位置開始,尋找字符 c
// 下面三個函數和前面三個 find 函數一致,只不過是從后往前查找
size_t rfind(const string& str, size_t pos = 0) const;
size_t rfind(const char* s, size_t pos = 0) const;
size_t rfind(char c, size_t pos = 0) const;// 不常用的與 string 對象操作相關的接口
string substr(size_t pos = 0, size_t len = npos) const;  // 返回當前 string 對象 pos 位置開始的長度為 len 的子串

(2)使用演示

// (6)與 string 對象操作相關的接口
void test6()
{string str("You are very good!");// 獲取 C 風格字符串const char* s = str.c_str();cout << "str = " << str << endl;cout << "s  = " << s << endl;// 在 str 中查找字符size_t pos = str.find('a');for (size_t i = pos; i < str.size(); ++i)cout << str[i];cout << endl;// 在 str 中查找字符串pos = str.find("very");for (size_t i = pos; i < str.size(); ++i)cout << str[i];cout << endl;
}

(3)運行結果
在這里插入圖片描述

7. string 類的關系運算符重載接口

??string 類重載了所有關系運算符,可以直接使用這些關系運算符對兩個 string 對象進行比較,這些接口會按照字典順序進行比較,返回布爾值。

(1)函數原型

// string 類關系運算符重載
bool operator<(const string& str) const;  // 當前 string 對象和 str 比較,若比 str 小則返回 true;否則返回 false
// 下面的接口同第一個接口
bool operator>(const string& str) const;
bool operator<=(const string& str) const;
bool operator>=(const string& str) const;
bool operator==(const string& str) const;
bool operator!=(const string& str) const;

(2)使用演示

// string 類關系運算符重載
void test7()
{string str1("C++");string str2("Java");// 開始比較cout << "str1 > str2 = " << (str1 > str2) << endl;cout << "str1 >= str2 = " << (str1 >= str2) << endl;cout << "str1 < str2 = " << (str1 < str2) << endl;cout << "str1 <= str2 = " << (str1 <= str2) << endl;cout << "str1 == str2 = " << (str1 == str2) << endl;cout << "str1 != str2 = " << (str1 != str2) << endl;
}

(3)運行結果
在這里插入圖片描述

8. string 類的輸入輸出

??string 類的對象可以直接使用 cin 和 cout 搭配流提取運算符(>>)和流插入運算符(<<)進行輸入和輸出,因為 string 類重載了流插入和流提取運算符。string 類和 C 風格字符串在使用 cin 和流提取運算符進行輸入時也只能輸入一個單詞,遇到空白就停止輸入。
??如果需要獲取多個單詞的輸入,就需要使用 istream 類的 getline 方法來獲取一行輸入。

(1)函數原型

istream& operator>>(istream& is, string& str);  // 流提取運算符重載
ostream& operator<<(ostream& os, const string& str);  // 流插入運算符重載

(2)使用演示

// (8)string 類的輸入輸出
void test8()
{string str;// 輸入一個單詞cout << "Please enter a word.\n";cin >> str;cout << "The word is " << str << endl;// 注意:上一次的輸入會把換行符留在輸入流,所以需要把遺留的換行符扔掉cin.get();// 輸入一句話cout << "Please enter a sentence.\n";getline(cin, str);cout << "The sentence is " << str << endl;
}

(3)運行結果
在這里插入圖片描述

三、與 string 類相關的精選習題

1. 把字符串轉換成整數(atoi)

題目鏈接:link

題目描述: 請你來實現一個 myAtoi(string s) 函數,使其能將字符串轉換成一個 32 位有符號整數(類似 C/C++ 中的 atoi 函數)。

函數 myAtoi(string s) 的算法如下:

  1. 讀入字符串并丟棄無用的前導空格
  2. 檢查下一個字符(假設還未到字符末尾)為正還是負號,讀取該字符(如果有)。 確定最終結果是負數還是正數。 如果兩者都不存在,則假定結果為正。
  3. 讀入下一個字符,直到到達下一個非數字字符或到達輸入的結尾。字符串的其余部分將被忽略。
  4. 將前面步驟讀入的這些數字轉換為整數(即,“123” -> 123, “0032” -> 32)。如果沒有讀入數字,則整數為 0 。必要時更改符號(從步驟 2 開始)。
  5. 如果整數數超過 32 位有符號整數范圍 [?231, 231 ? 1] ,需要截斷這個整數,使其保持在這個范圍內。具體來說,小于 ?231 的整數應該被固定為 ?231 ,大于 231 ? 1 的整數應該被固定為 231 ? 1 。
  6. 返回整數作為最終結果。

注意:
本題中的空白字符只包括空格字符 ’ ’ 。
除前導空格或數字后的其余字符串外,請勿忽略 任何其他字符。

示例:
在這里插入圖片描述
提示:=

  1. 0 <= s.length <= 200
  2. s 由英文字母(大寫和小寫)、數字(0-9)、’ ‘、’+‘、’-’ 和 ‘.’ 組成

(1)解題思路:

  1. 首先使用 while 循環跳過前面的前導空格;
  2. 使用 if 語句檢查下一個非空格字符是否為負號,如果不是負號則為正數;
  3. 開始讀取數字,直到遇到第一個非數字字符。如果沒有數字字符,則為 0;
  4. 如果整數超過 INT_MAX 則為 INT_MAX,如果整數小于 INT_MIN 則為 INT_MIN;
  5. 返回結果整數。

(2)解題代碼:

class Solution {
public:int myAtoi(string str) {// 舍棄前面的前導空格int i = 0;while (' ' == str[i])++i;// 判斷正負號int flag = 1;if ('-' == str[i]){flag = -1;++i;}else if ('+' == str[i]){flag = 1;++i;}// 開始計算int len = str.size();long long result = 0;while (i < len){// 是數字字符則加入計算if (isdigit(str[i])){result = result * 10 + str[i] - '0';// 判斷計算結果if (result > INT_MAX){if (1 == flag)return INT_MAX;elsereturn INT_MIN;}}else  // 否則結束計算{break;}// 下一個字符++i;}// 返回計算結果return result * flag;}
};

2. 字符串相加

題目鏈接:link

題目描述:

  1. 給定兩個字符串形式的非負整數 num1 和num2 ,計算它們的和并同樣以字符串形式返回。
  2. 你不能使用任何內建的用于處理大整數的庫(比如 BigInteger), 也不能直接將輸入的字符串轉換為整數形式。

示例:
在這里插入圖片描述

提示:

  1. 1 <= num1.length, num2.length <= 104
  2. num1 和num2 都只包含數字 0-9
  3. num1 和num2 都不包含任何前導零

(1)解題思路:

  1. 參考數字的加法運算,從兩個字符串的最后一個字符開始相加,分別計算當前位置和進位,然后把當前位置拼接到結果字符串中,直到其中一個字符串達到末尾;
  2. 把剩下沒到末尾的字符串剩下的字符繼續拼接到結果字符串中,最后把整個字符串逆置;
  3. 返回結果字符串。

(2)解題代碼:

class Solution {
public:string addStrings(string num1, string num2) {// 所需變量string result;int i1 = num1.size() - 1, i2 = num2.size() - 1;int carry = 0;// 開始拼接while (i1 >= 0 || i2 >= 0){// 計算當前兩位int n1 = (i1 >= 0? num1[i1--] - '0' : 0);int n2 = (i2 >= 0? num2[i2--] - '0' : 0);// 拼接result += (n1 + n2 + carry) % 10 + '0';// 計算進位carry = (n1 + n2 + carry) / 10;}// 如果兩個字符串同時結束,但是 carry 不為 0if (carry)result += carry + '0';// 逆置結果字符串reverse(result.begin(), result.end());// 返回結果字符串return result;}
};

3. 僅僅反轉字母

題目鏈接:link

題目描述: 給你一個字符串 s ,根據下述規則反轉字符串:

  1. 所有非英文字母保留在原有位置。
  2. 所有英文字母(小寫或大寫)位置反轉。
  3. 返回反轉后的 s 。

示例:
在這里插入圖片描述
提示:
4. 1 <= s.length <= 100
5. s 僅由 ASCII 值在范圍 [33, 122] 的字符組成
6. s 不含 ‘"’ 或 ‘\’

(1)解題思路:

  1. 使用兩個指針,分別指向字符串的首尾,當兩個指針未相遇并且都指向字母字符時交換,當兩個指針相遇或者錯開時則結束;
  2. 返回交換完畢的字符串;

(2)解題代碼:

class Solution {
public:string reverseOnlyLetters(string s) {int left = 0, right = s.size() - 1;// 開始交換while (left < right){// 左右尋找字母字符while (left < right && !isalpha(s[left]))++left;while (left < right && !isalpha(s[right]))--right;// 交換swap(s[left], s[right]);// 下一組++left;--right;}// 返回交換完成的字符串return s;}
};

4. 字符串中的第一個唯一字符

題目鏈接:link

題目描述: 給定一個字符串 s ,找到 它的第一個不重復的字符,并返回它的索引 。如果不存在,則返回 -1 。

示例:
在這里插入圖片描述
提示:

  1. 1 <= s.length <= 105
  2. s 只包含小寫字母

(1)解題思路:

  1. 由于字符串只有小寫字母,那么創建一個包含 26 個元素的 int 數組,對應 26 個小寫字母的出現次數;
  2. 遍歷一遍數組,計算每個字符出現的次數,再遍歷一遍數組,找出第一個出現一次的字符;
  3. 返回對應的下標;

(2)解題代碼:

class Solution {
public:int firstUniqChar(string s) {int times[26] = {0};// 計算每個字符出現的次數for (const auto& e : s){++times[e - 'a'];}// 找到第一個出現一次的字符int len = s.size();for (int i = 0; i < len; ++i){if (1 == times[s[i] - 'a'])return i;}// 沒有找到返回 -1return -1;}
};

5. 字符串最后一個單詞的長度

題目鏈接:link

題目描述: 對于給定的若干個單詞組成的句子,每個單詞均由大小寫字母混合構成,單詞間使用單個空格分隔。輸出最后一個單詞的長度。

輸入描述:
在一行上輸入若干個字符串,每個字符串代表一個單詞,組成給定的句子。
除此之外,保證每個單詞非空,由大小寫字母混合構成,且總字符長度不超過 103

輸出描述:
在一行上輸出一個整數,代表最后一個單詞的長度。

(1)解題思路:

  1. 創建一個 string 對象接受輸入,每次輸入一個單子并計算其長度,直到遇到換行符;
  2. 返回此時的長度,也就是最后一個單詞的長度。

(2)解題代碼:

// 頭文件
#include <iostream>
#include <string>// using 聲明
using std::string;
using std::cin;
using std::cout;
using std::endl;int main() {int len = 0;string str;// 輸入單詞并計算長度while (cin >> str){len = str.size();}// 輸出最后一個單詞的長度cout << len << endl;
}
// 64 位輸出請用 printf("%lld")

6. 驗證回文串

題目鏈接:link

題目描述: 如果在將所有大寫字符轉換為小寫字符、并移除所有非字母數字字符之后,短語正著讀和反著讀都一樣。則可以認為該短語是一個 回文串 。

字母和數字都屬于字母數字字符。

給你一個字符串 s,如果它是 回文串 ,返回 true ;否則,返回 false 。

示例:
在這里插入圖片描述

提示:

  1. 1 <= s.length <= 2 * 105
  2. s 僅由可打印的 ASCII 字符組成

(1)解題思路:

  1. 首先遍歷一遍字符串,把所有大寫字母轉換成小寫字母,然后把所有字母數字字符拼接到一個新的字符串后頭;
  2. 然后使用兩個指針正著和倒著遍歷來驗證新的字符串是否為回文字符串;
  3. 返回驗證的結果;

(2)解題代碼:

class Solution {
public:bool isPalindrome(string s) {string tmp;// 小寫轉大寫并把所有的字母數字字符拼接到新的字符串后面for (int i = 0; i < s.size(); ++i){if (isalnum(s[i])){tmp += tolower(s[i]);}}// 驗證新的字符串int left = 0, right = tmp.size() - 1;while (left < right){// 判斷當前這組字符if (tmp[left] != tmp[right]){return false;}// 下一組字符++left;--right;}// 是回文串return true;}
};

7. 反轉字符串Ⅱ

題目鏈接:link

題目描述: 給定一個字符串 s 和一個整數 k,從字符串開頭算起,每計數至 2k 個字符,就反轉這 2k 字符中的前 k 個字符。

如果剩余字符少于 k 個,則將剩余字符全部反轉。
如果剩余字符小于 2k 但大于或等于 k 個,則反轉前 k 個字符,其余字符保持原樣。

示例:
在這里插入圖片描述

提示:

  1. 1 <= s.length <= 104
  2. s 僅由小寫英文組成
  3. 1 <= k <= 104

(1)解題思路:

  1. while 循環,前后指針法,cur 指針往前走,pre 指針不動,當 cur 指針與 pre 指針的距離達到 2k-1 時,逆置前 k 個字符并更新 pre 指針的位置;
  2. 當 cur >= s.size() 時跳出循環,并根據此時 cur - pre 的值判斷最后一組的情況;
  3. 返回逆置完成的字符串。

(2)解題代碼:

// 逆置函數
void reverse(char* left, char* right)
{while (left < right){char tmp = *left;*left = *right;*right = tmp;// 下一組++left;--right;}
}class Solution {
public:string reverseStr(string s, int k) {// 使用前后指針遍歷字符串,每當兩個指針相隔 2k 時,反轉int pre = 0, cur = 0;int len = s.size();while (cur < len){if (cur - pre == 2 * k - 1){// 反轉前 k 個字符reverse(&s[pre], &s[pre + k - 1]);// 更新 prepre = cur + 1;}// cur 前進++cur;}// 判斷最后的一段字符if (cur - pre < k)reverse(&s[pre], &s[cur - 1]);elsereverse(&s[pre], &s[pre + k - 1]);// 返回逆置完畢的字符串return s;}
};

8. 反轉字符串中的單詞Ⅲ

題目鏈接:link

題目描述: 給定一個字符串 s ,你需要反轉字符串中每個單詞的字符順序,同時仍保留空格和單詞的初始順序。

示例:
在這里插入圖片描述

提示:

  1. 1 <= s.length <= 5 * 104
  2. s 包含可打印的 ASCII 字符。
  3. s 不包含任何開頭或結尾空格。
  4. s 里 至少 有一個詞。
  5. s 中的所有單詞都用一個空格隔開。

(1)解題思路:

  1. while 循環,前后指針法,pre 不動,cur 前進,當 cur 遇到空格時,逆置前面的單詞后更新 pre,直到 cur 超出 s 末尾;
  2. 返回逆置完畢的 s。

(2)解題代碼:

// 逆置函數
void reverse(char* left, char* right)
{while (left < right){char tmp = *left;*left = *right;*right = tmp;// 下一組++left;--right;}
}class Solution {
public:string reverseWords(string s) {int pre = 0, cur = 0, len = s.size();while (cur < len){// 如果 cur 是空格,則逆置前面的單詞if (' ' == s[cur]){reverse(&s[pre], &s[cur-1]);// 更新 prepre = cur + 1;}// cur 前進++cur;}// 逆置最后一個單詞reverse(&s[pre], &s[cur-1]);// 返回逆置的字符串return s;}
};

9. 字符串相乘

題目鏈接:link

題目描述: 給定兩個以字符串形式表示的非負整數 num1 和 num2,返回 num1 和 num2 的乘積,它們的乘積也表示為字符串形式。

示例:
在這里插入圖片描述
提示:

  1. 1 <= num1.length, num2.length <= 200
  2. num1 和 num2 只能由數字組成。
  3. num1 和 num2 都不包含任何前導零,除了數字0本身。

(1)解題思路:

  1. 用其中一個字符串的每一位去乘以另一個字符串,然后把結果存在一個臨時字符串中,最后加到結果字符串中去;
  2. 需要對不同的位進行補 0,個位不補,十位補一個 0,以此類推;
  3. 字符串的加法前面的習題中已經寫過了,本題只是在其基礎上進行了一些復雜的變化,難度沒有什么提升;
  4. 返回最終的結果字符串。

(2)解題代碼:
??本題思路沒有問題,但是代碼寫的一般般,大家可以參考自己修改完善一下。

// 字符串相加函數
string add_string(const string& num1, const string& num2)
{// 所需變量int i1 = num1.size() - 1;int i2 = num2.size() - 1;int carry = 0;string result;// 開始相加while (i1 >= 0 || i2 >= 0){// 計算兩個數字字符串當前位的值int n1 = (i1 >= 0 ? num1[i1] - '0' : 0);int n2 = (i2 >= 0 ? num2[i2] - '0' : 0);// 計算當前位int cur = n1 + n2 + carry;// 拼接當前位result += cur % 10 + '0';// 計算進位carry = cur / 10;// 下一組位--i1;--i2;} // 判斷是否存在進位if (carry)result += carry + '0';// 逆置reverse(result.begin(), result.end());// 返回結果return result;
}class Solution {
public:string multiply(string num1, string num2) {// 若一個數為 0,則結果為 0if ("0" == num1 || "0" == num2)return "0";// 所需變量int i = num1.size() - 1;string result;// 用 num1 的每一位去乘以 num2while (i >= 0){char cur = num1[i];string cur_result;int carry = 0;// 當前位開始相乘for (int j = num2.size() - 1; j >= 0; --j){// 相乘int mul = (cur - '0') * (num2[j] - '0') + carry;// 計算本位并拼接到當前結果cur_result += mul % 10 + '0';// 計算進位carry = mul / 10;}// 補上進位if (carry)cur_result += carry + '0';// 逆置當前結果reverse(cur_result.begin(), cur_result.end());// 補零int n = num1.size() - i - 1;while (n--)cur_result += '0';// 把當前結果加到最終結果result = add_string(result, cur_result);// 下一位--i;}// 返回相乘的結果return result;}
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70276.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70276.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70276.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unreal5從入門到精通之在編輯器中更新 UserWidgets

前言 在虛幻中創建越來越復雜和靈活的 UserWidget 藍圖時,一個問題是它們在編輯器中的外觀與它們在游戲中的最終外觀可能有很大不同。 庫存面板示例 假設你想創建一個通用的庫存顯示小部件。我們可以在整個 UI 中使用它,無論我們需要在哪里顯示某些內容。 標題,描述所顯示…

計算機網絡-OSI七層參考模型與數據封裝,網絡安全零基礎入門到精通實戰教程!

目錄 一、網絡 1、網絡的定義 2、網絡的分類 3、網絡的作用 4、網絡的數據傳輸方式 5、網絡的數據通訊方式 二、OSI七層參考模型 1、網絡參考模型定義 2、分層的意義 3、分層與功能 4、TCP\IP五層模型 三、參考模型的協議 1、物理層 2、數據鏈路層 3、網絡層 4…

Python正則替換終極指南:用re.sub玩轉字符串魔法

Python正則替換終極指南&#xff1a;用re.sub玩轉字符串魔法 一、為什么re.sub是文本處理的瑞士軍刀&#xff1f; 在Python的re模塊中&#xff0c;re.sub()的周下載量突破5800萬次&#xff08;2025年PyPI數據&#xff09;&#xff0c;它實現了&#xff1a; &#x1f4cd; 模…

gen_gauss_filter用于檢測帶方向的線條

目錄 一、核心參數分析 1.1 方向覆蓋范圍 1.2 濾波器方向帶寬 二、角度配置建議 三、參數選擇依據 四、實施建議 五、模擬圖測試(項目圖檔不好直接分享) 5.1 模擬圖制作 5.2 檢測偽代碼 在Halcon中使用高斯濾波器檢測多方向線條時,角度參數的選取需要綜合考慮濾波…

C++17 中的 std::to_chars 和 std::from_chars:高效且安全的字符串轉換工具

文章目錄 1. 傳統轉換方法的局限性2. std::to_chars&#xff1a;數值到字符串的高效轉換函數原型&#xff1a;返回值&#xff1a;示例代碼&#xff1a;輸出&#xff1a; 3. std::from_chars&#xff1a;字符串到數值的高效解析函數原型&#xff1a;返回值&#xff1a;示例代碼&…

深入學習解析:183頁可編輯PPT華為市場營銷MPR+LTC流程規劃方案

華為終端正面臨銷售模式轉型的關鍵時刻&#xff0c;旨在通過構建MPRLTC項目&#xff0c;以規避對運營商定制的過度依賴&#xff0c;并探索新的增長路徑。項目核心在于建設一套全新的銷售流程與IT系統&#xff0c;支撐雙品牌及自有品牌的戰略發展。 項目總體方案聚焦于四大關鍵議…

Python正則表達式處理中日韓字符過濾全解析

Python正則表達式處理中日韓字符過濾全解析 一、核心原理&#xff1a;Unicode字符范圍定位 中日韓字符在Unicode中的分布&#xff1a; 中文&#xff1a;\u4e00-\u9fff&#xff08;基本區&#xff09; \u3400-\u4dbf&#xff08;擴展A區&#xff09; \U00020000-\U0002a6df…

基于WOA鯨魚優化的WSN網絡最優節點部署算法matlab仿真

目錄 1.程序功能描述 2.測試軟件版本以及運行結果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 鯨魚優化算法&#xff08;WOA&#xff09;是一種模擬座頭鯨捕食行為的元啟發式優化算法。其主要原理基于座頭鯨獨特的 “氣泡網” 捕食策略&#xff0c;通過數學模…

【數據分析】3 數據分析成長之路

職業發展路徑&#xff1a; 向上發展&#xff08;技術方向&#xff09;&#xff1a;可以詳細說明成為數據科學家或專家所需的具體技能和步驟&#xff0c;包括學習的算法、工具等。向下發展&#xff08;業務方向&#xff09;&#xff1a;可以探討結合業務知識的具體領域&#xff…

excel導入Mysql中時間格式異常

問題描述&#xff1a; 當使用xls/xlsx/csv導入mysql中&#xff0c;如果列是時間類型比如excel表中顯示2024/02/20 09:18:00&#xff0c;導入后時間可能就會變成1900-01-01 09:18:00這樣。 問題原因&#xff1a; 這是由于excel表中和數據庫中的時間類型不匹配導致。 問題解決…

async checkpointing

Reducing Model Checkpointing Times by Over 10x with PyTorch Distributed Asynchronous Checkpointing | PyTorch 最初來源&#xff1a;IBM Research 核心思想&#xff1a;GPU->CPU&#xff0c;用的是blocking&#xff1b;CPU->Disk&#xff0c;用的是異步不阻塞訓練…

Nginx穩定版最新1.26.2源碼包安裝【保姆級教學】

Nginx安裝及配置 開源Nginx官網地址(https://nginx.org) Nginx源碼包下載地址(https://nginx.org/en/download.html) Mainline version 主線版本 Stable version 穩定版本 Legacy versions 陳舊版本 下載Nginx源碼文件 curl -O https://nginx.org/download/nginx-1.26.2.t…

在ubuntu上用Python的openpyxl模塊操作Excel的案例

文章目錄 安裝模塊讀取Excel數據庫取數匹配數據和更新Excel數據 在Ubuntu系統的環境下基本職能借助Python的openpyxl模塊實現對Excel數據的操作。 安裝模塊 本次需要用到的模塊需要提前安裝(如果沒有的話) pip3 install openpyxl pip3 install pymysql在操作前&#xff0c;需…

GeoHD - 一種用于智慧城市熱點探測的Python工具箱

GeoHD - 一種用于智慧城市熱點探測的Python工具箱 詳細原理請參考&#xff1a;Yan, Y., Quan, W., Wang, H., 2024. A data‐driven adaptive geospatial hotspot detection approach in smart cities. Trans. GIS tgis.13137. 代碼下載&#xff1a;下載 1. 簡介 在城市數據…

16 中介者(Mediator)模式

中介者模式 1.1 分類 &#xff08;對象&#xff09;行為型 1.2 提出問題 實現一個機場的起飛管理系統&#xff0c;如果由駕駛員們討論誰先飛&#xff0c;后果可能是災難性的。 1.3 解決方案 用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用&a…

最薄的機身,游最深的海

經濟全球化的潮流&#xff0c;勢不可擋。 “技術、通訊和全球化&#xff0c;正在消除傳統的地理和經濟邊界&#xff0c;使競爭環境趨于平等。”《世界是平的》作者托馬斯弗里德曼預言的"扁平化競爭"正加速演進。 在高端智能手機戰場&#xff0c;一場由中國企業主導…

【HarmonyOS Next】鴻蒙監聽手機按鍵

【HarmonyOS Next】鴻蒙監聽手機按鍵 一、前言 應用開發中我們會遇到監聽用戶實體按鍵&#xff0c;或者擴展按鍵的需求。亦或者是在某些場景下&#xff0c;禁止用戶按下某些按鍵的業務需求。 這兩種需求&#xff0c;鴻蒙都提供了對應的監聽事件進行處理。 onKeyEvent 默認的…

IC設計版圖中GDS2文件格式詳解

版圖中GDS2文件格式詳解 目錄 什么是GDS2文件&#xff1f;GDS2文件的歷史與發展GDS2文件的結構解析GDS2文件的核心元素GDS2 vs. OASIS: 核心差異如何生成與查看GDS2文件&#xff1f;GDS2文件的局限性應用場景總結 什么是GDS2文件&#xff1f; GDS2&#xff08;Graphic Data …

KMP算法:字符串匹配的智慧跳躍

文章目錄 起因&#xff1a;暴力法的致命缺陷暴力搜索的局限性 KMP核心思想&#xff1a;避免重復理解前綴表&#xff08;PMT&#xff09;不匹配時的回退機制代碼&#xff1a;高效字符串匹配補充&#xff1a;next表和PMT表 暴力法 vs KMP總結&#xff1a;KMP 是如何改變游戲規則的…

上位機知識篇---setuptools

文章目錄 前言簡介一、核心功能1.依賴管理自動安裝依賴版本約束額外依賴組命令行工具插件系統 2.開發模式安裝3.資源文件管理4.Egg 分發&#xff08;已逐漸被 Wheel 取代&#xff09;5.命名空間包 二、基礎用法1. 項目結構示例2. 配置文件 setup.cfg3. setup.py 最小化示例&…