回文判断双指针法:left=0、right=s.length()-1,循环比较s[left]与s[right],不等返回false,相等则left++、right--,直至left>=right;空串和单字符均视为回文。

用 std::string 双指针判断回文最直接
只要字符串本身不带空格、标点或大小写混杂,直接首尾比对就行。定义两个索引,left 从 0 开始,right 从 s.length() - 1 开始,每次比较 s[left] 和 s[right],不等就返回 false;相等则 left++、right-- 继续,直到 left >= right。
常见错误是忘记边界条件:空字符串和单字符都是回文,但有人会写成 while (left 却漏掉 <code>== 的情况——其实没问题,因为 已覆盖所有需比对的对;真正容易错的是越界访问,比如用 <code>s.at(i) 而不是 s[i],抛异常反而打断流程。
示例:
bool isPalindrome(const std::string& s) {
int left = 0, right = s.size() - 1;
while (left < right) {
if (s[left] != s[right]) return false;
left++;
right--;
}
return true;
}忽略大小写和非字母数字时要用 std::isalnum 和 std::tolower
现实中的回文(如 "A man a plan a canal Panama")需要预处理:跳过空格、标点,统一转小写再比。C++ 标准库提供 std::isalnum 判断是否为字母或数字,std::tolower 转小写(注意必须传 unsigned char,否则负值 char 可能 UB)。
立即学习“C++免费学习笔记(深入)”;
关键点:
- 不能先过滤再比——那样要额外分配内存;双指针边走边跳更高效
- 每次移动前先用
while跳过非法字符,但必须检查left ,否则越界 -
std::tolower对非字母数字字符行为未定义,所以只对std::isalnum返回 true 的字符调用
示例片段:
while (left < right && !std::isalnum(static_cast<unsigned char>(s[left]))) left++;
while (left < right && !std::isalnum(static_cast<unsigned char>(s[right]))) right--;
if (std::tolower(static_cast<unsigned char>(s[left])) !=
std::tolower(static_cast<unsigned char>(s[right]))) return false;用 std::reverse 创建副本判断适合简单场景
如果只是快速验证、且字符串不长,可以拷贝一份再反转,然后比较原串和反转串:std::string rev = s; std::reverse(rev.begin(), rev.end()); return s == rev;。优点是逻辑清晰、不易出错;缺点是空间开销翻倍,且对大字符串或高频调用不友好。
注意:std::reverse 修改原容器,所以必须先拷贝;如果误写成 std::reverse(s.begin(), s.end()) 再比,就破坏了原始数据。
另外,std::string 的 == 比较是逐字符 O(n),和双指针一样时间复杂度,但常数更大(要遍历两次)。
Unicode 字符串回文判断不能只靠 char 索引
上面所有方法都假设字符串是 ASCII 或 UTF-8 编码但按字节操作——这对中文、emoji 等多字节字符完全失效。例如 UTF-8 中 'é' 占 2 字节,s[0] 和 s[1] 都不是完整字符。
真要支持 Unicode,得先用 ICU 或 std::codecvt_utf8(已弃用)做字符级切分,或者用 C++20 的 std::ranges::utf8_view(需编译器支持)。多数项目实际只需 ASCII 子集,强行上 Unicode 处理反而引入依赖和复杂度。
所以除非明确要求支持中文/emoji 回文,否则别碰 UTF-8 字符边界——先确认需求再决定要不要升级处理逻辑。


















