用std::set统计字符最直观但非最优;布尔数组性能更好,推荐std::array+std::all_of;位运算压缩状态适合极致优化。

用 std::set 统计字符出现情况最直观
直接遍历字符串,把每个字母(转成小写)插入 std::set<char></char>,最后检查集合大小是否为 26。适合调试或逻辑验证,但不是性能最优解。
- 必须先用
std::tolower统一大小写,否则'A'和'a'被视为不同字符 -
std::set自动去重,插入重复字母不会影响 size - 遇到非字母字符(如空格、数字)可跳过,用
std::isalpha判断 - 示例:若
s = "The quick brown fox jumps over the lazy dog",处理后seen.size() == 26
用布尔数组做标记,性能更好且更常用
声明长度为 26 的 bool seen[26] = {},遍历字符串时,对每个字母计算 c - 'a'(需确保是小写字母),设对应位置为 true,最后遍历数组确认全为 true。
- 必须提前把字母转成小写,否则
'A' - 'a'是负数,越界访问 - 推荐用
std::array<bool></bool>替代裸数组,更安全;初始化用{}确保全false - 检查时用
std::all_of(seen.begin(), seen.end(), [](bool b) { return b; })比手写循环更简洁 - 比
std::set快——没有内存分配、无红黑树开销,O(n) 时间 + O(1) 空间
用位运算压缩状态,适合嵌入式或极致优化场景
用一个 uint32_t(至少 32 位)变量当 bitmap,每位代表一个字母:bit[i] 对应 'a' + i。每遇到一个字母,执行 mask |= (1U ,最后判断 <code>mask == 0x3FFFFFFU(即低 26 位全 1)。
-
0x3FFFFFFU是 26 个 1 的十六进制表示(0b11111111111111111111111111),不能写成0x7FFFFFFF(那是 31 个 1) - 务必确保
c是小写字母,否则位移可能超范围,引发未定义行为 - 不依赖 STL 容器,栈上仅占 4 字节,无动态分配,在资源受限环境有优势
- 可扩展为支持大小写分别检测:用两个
uint32_t,或一个uint64_t
忽略大小写和非字母字符是常见误判点
很多人直接比较 std::string::find 或用 std::count,结果漏掉大小写转换,或把标点符号当有效字符统计,导致假阳性或假阴性。
-
s.find('a') != std::string::npos这类写法要写 26 次,既啰嗦又低效,还容易漏字母 - 没过滤非字母字符时,
"abcdefghijklmnopqrstuvwxyz0123"会被误判为“含全部字母”——其实它确实含,但逻辑上你通常只关心字母本身 - 用
std::locale做大小写转换不如std::tolower(c, std::locale())可靠,尤其在非 C locale 下;简单场景用std::tolower(c)(传unsigned char)足够 - 边界情况:空字符串、全是数字、只有大写字母——都得正确返回
false
真正难的不是写出来,而是想清楚“什么是字母”“要不要区分大小写”“非字母怎么处理”,这些决定后续所有实现细节。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











