💓 博客主页:倔强的石头的CSDN主页****
📝Gitee主页:倔强的石头的gitee主页****
⏩ 文章专栏:C++经典例题
期待您的关注
目录
[二、解法一:将字母数字连接到新的 string](#二、解法一:将字母数字连接到新的 string)
一、问题描述
在字符串处理中,判断一个字符串是否为回文串是一个经典问题。
本题有特殊要求:在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,如果短语正着读和反着读都一样,则认为该短语是一个回文串。字母和数字都属于字母数字字符。
示例
- 输入:
s = "A man, a plan, a canal: Panama"
,输出:true
,解释:处理后得到"amanaplanacanalpanama"
是回文串。 - 输入:
s = "race a car"
,输出:false
,解释:处理后得到"raceacar"
不是回文串。 - 输入:
s = " "
,输出:true
,解释:移除非字母数字字符后,s
是一个空字符串""
,空字符串正着反着读都一样,所以是回文串。
原题链接
二、解法一:将字母数字连接到新的 string
思路
这种方法的核心思想是先遍历原字符串,把其中的字母数字字符提取出来,同时将大写字母转换为小写字母,存储到一个新的字符串 tmp
中
然后再对新字符串 tmp
进行回文判断
代码实现
cpp
#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,并且统一为小写
{
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是处理后新字符串的长度。
三、解法二:直接原地筛选判断
思路
这种方法不创建新的字符串,而是直接在原字符串上使用双指针法进行筛选和判断。通过两个指针 left
和 right
分别从字符串的两端开始向中间移动,跳过非字母数字字符,同时将字符转换为小写后进行比较。
代码实现
cpp
#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;
}
}
//跳出循环,要么left==right,要么left>right
//说明所有需要比较的字符对都已经检查过,且都相等
return true;
}
};
代码解释
- 初始化指针 :使用迭代器
left
指向字符串的开头,right
指向字符串的结尾。 - 跳过非字母数字字符 :通过两个内层
while
循环,分别将left
和right
指针移动到字母数字字符的位置。 - 字符比较 :将
left
和right
指针指向的字符转换为小写后进行比较,如果不相等,返回false
;如果相等,继续移动指针。 - 返回结果 :当
left
大于等于right
时,说明所有需要比较的字符对都已经检查过,且都相等,返回true
。
复杂度分析
- 时间复杂度:O(n),只需要遍历一次字符串。
- 空间复杂度:O(1),只使用了常数级的额外空间。
总结
两种解法都能有效解决回文串判断问题:
解法一逻辑清晰,易于理解,但需要额外的空间存储处理后的字符串;
解法二原地操作,空间复杂度更低,更适合处理大规模数据。在实际应用中,可以根据具体需求选择合适的解法。