C++實現回文串判斷的兩種高效方法
一、問題描述
在字符串處理中,判斷一個字符串是否為回文串是一個經典問題。
本題有特殊要求:在將所有大寫字符轉換為小寫字符、并移除所有非字母數字字符之后,如果短語正著讀和反著讀都一樣,則認為該短語是一個回文串。字母和數字都屬于字母數字字符。
示例
- 輸入:
s = "A man, a plan, a canal: Panama"
,輸出:true
,解釋:處理后得到"amanaplanacanalpanama"
是回文串。 - 輸入:
s = "race a car"
,輸出:false
,解釋:處理后得到"raceacar"
不是回文串。 - 輸入:
s = " "
,輸出:true
,解釋:移除非字母數字字符后,s
是一個空字符串""
,空字符串正著反著讀都一樣,所以是回文串。
原題鏈接
二、解法一:將字母數字連接到新的 string
思路
這種方法的核心思想是先遍歷原字符串,把其中的字母數字字符提取出來,同時將大寫字母轉換為小寫字母,存儲到一個新的字符串 tmp
中
然后再對新字符串 tmp
進行回文判斷
代碼實現
#include <iostream> #include <string> class Solution { public: bool isPalindrome(string s) //第一種方式 將字母數字連接到新的string { string tmp; string::iterator left = s.begin(); string::iterator right = s.end(); while (left != right)//第一次遍歷,所有字母數字轉入新string,并且統(tǒng)一為小寫 { if ((*left >= '0' && *left <= '9') || (*left >= 'a' && *left <= 'z')) tmp += *left; if (*left >= 'A' && *left <= 'Z') tmp += (*left + 32); ++left; } if (tmp.empty())//如果新string為空,則判定為回文串 return true; left = tmp.begin(); right = tmp.end() - 1; while (left <= right)//第二次遍歷 左右迭代器逐個對比 { if (*left == *right) { ++left; --right; } else return false; } return true; } };
代碼解釋
- 提取字母數字并轉換大小寫:
- 定義一個空字符串
tmp
用于存儲處理后的字符。 - 使用迭代器
left
遍歷原字符串s
,當遇到數字('0'
到'9'
)或小寫字母('a'
到'z'
)時,直接添加到tmp
中;當遇到大寫字母('A'
到'Z'
)時,將其 ASCII 碼值加 32 轉換為小寫字母后添加到tmp
中。
- 定義一個空字符串
- 處理空字符串情況:如果
tmp
為空字符串,根據題目定義,空字符串是回文串,直接返回true
。 - 回文判斷:使用雙指針法,
left
指向tmp
的開頭,right
指向tmp
的結尾,逐個比較對應位置的字符。如果不相等,返回false
;如果都相等,最終返回true
。
復雜度分析
- 時間復雜度:O(n)需要遍歷原字符串一次,再遍歷新字符串一次。
- 空間復雜度:O (n),其中 n是處理后新字符串的長度。
三、解法二:直接原地篩選判斷
思路
這種方法不創(chuàng)建新的字符串,而是直接在原字符串上使用雙指針法進行篩選和判斷。通過兩個指針 left
和 right
分別從字符串的兩端開始向中間移動,跳過非字母數字字符,同時將字符轉換為小寫后進行比較。
代碼實現
#include <iostream> #include <string> #include <cctype> class Solution { public: bool isPalindrome(std::string s) //第二種方式,直接原地篩選判斷 { string::iterator left = s.begin(); string::iterator right = s.end() - 1; while (left < right) { // 跳過左邊的非字母數字字符 while (left < right && !isalnum(*left)) { ++left; } // 跳過右邊的非字母數字字符 while (left < right && !isalnum(*right)) { --right; } if (left < right) { // 將字符轉換為小寫后比較 if (tolower(*left) != tolower(*right)) { return false; } ++left; --right; } } //跳出循環(huán),要么left==right,要么left>right //說明所有需要比較的字符對都已經檢查過,且都相等 return true; } };
代碼解釋
- 初始化指針:使用迭代器
left
指向字符串的開頭,right
指向字符串的結尾。 - 跳過非字母數字字符:通過兩個內層
while
循環(huán),分別將left
和right
指針移動到字母數字字符的位置。 - 字符比較:將
left
和right
指針指向的字符轉換為小寫后進行比較,如果不相等,返回false
;如果相等,繼續(xù)移動指針。 - 返回結果:當
left
大于等于right
時,說明所有需要比較的字符對都已經檢查過,且都相等,返回true
。
復雜度分析
- 時間復雜度:O(n),只需要遍歷一次字符串。
- 空間復雜度:O(1),只使用了常數級的額外空間。
總結
兩種解法都能有效解決回文串判斷問題:
解法一邏輯清晰,易于理解,但需要額外的空間存儲處理后的字符串;
解法二原地操作,空間復雜度更低,更適合處理大規(guī)模數據。在實際應用中,可以根據具體需求選擇合適的解法。
以上就是C++實現回文串判斷的兩種高效方法的詳細內容,更多關于C++回文串判斷的資料請關注腳本之家其它相關文章!
相關文章
C++中CopyFile和MoveFile函數使用區(qū)別的示例分析
這篇文章主要介紹了C++中CopyFile和MoveFile函數使用區(qū)別的示例分析,CopyFile表示將文件A拷貝到B,如果B已經存在則覆蓋,MoveFile表示將文件A移動到。對此感興趣的可以來了解一下2020-07-07C++調用C函數報錯無法解析的外部命令/無法解析的外部符號問題
這篇文章主要介紹了C++調用C函數報錯無法解析的外部命令/無法解析的外部符號問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08