1. 字符串处理基础:三道经典C++题目解析
作为程序员,字符串处理是我们日常工作中最常遇到的基础技能之一。今天我想分享三个经典的字符串处理题目,它们不仅能够帮助我们巩固C++字符串操作的基本功,还能让我们理解如何高效处理各种字符串场景。这三个题目分别是手机短号生成、字符串统计和算术作业检查,涵盖了字符串截取、字符遍历和复杂字符串解析等核心技能。
2. 手机短号生成问题
2.1 问题理解与需求分析
手机短号问题要求我们将11位手机号码转换为特定格式的短号。根据题目描述,短号的生成规则非常简单:在手机号后5位数字前加上数字"6"。例如,手机号13512345678对应的短号就是645678。
这个问题的核心在于:
- 输入是固定长度的字符串(11位数字)
- 输出需要特定位置的子串加上前缀字符
- 需要处理多组输入并保持输出顺序
2.2 解决方案设计
我采用了以下解决思路:
- 使用字符串类型存储手机号,避免数值类型处理可能带来的前导零丢失问题
- 利用字符串的substr方法直接提取后5位
- 在提取的子串前拼接字符'6'
关键点在于认识到:
- 手机号作为字符串处理比作为整数处理更合适
- 字符串索引从0开始,后5位对应的索引是6到10
- 不需要任何数值计算,纯字符串操作即可
2.3 完整代码实现
cpp复制#include <bits/stdc++.h>
using namespace std;
int main(){
int N;
cin >> N;
string phone;
while(N--){
cin >> phone; // 读取11位手机号
string shortNum = "6" + phone.substr(6, 5); // 取后5位并加上6
cout << shortNum << endl;
}
return 0;
}
2.4 关键技术与注意事项
-
substr方法使用:
- 第一个参数是起始位置(从0开始)
- 第二个参数是子串长度
- 这里phone.substr(6,5)表示从索引6开始取5个字符
-
输入输出处理:
- 先读取数据组数N
- 使用while循环处理N组数据
- 每组数据独立处理,互不影响
-
常见陷阱:
- 忘记处理多组数据,只读取了一组
- substr参数错误,如写成phone.substr(6,6)会越界
- 使用整数类型存储手机号可能导致前导零丢失
提示:在实际工程中,还应该增加输入验证,确保手机号确实是11位数字,避免非法输入导致程序异常。
3. 字符串统计问题
3.1 问题理解与需求分析
字符串统计问题要求我们统计给定字符串中小写字母的出现次数。这个问题看似简单,但涉及几个关键点:
- 需要区分大小写,只统计小写字母
- 字符串中可能包含数字、大写字母和其他字符
- 需要处理多行输入
3.2 解决方案设计
我的解决思路是:
- 遍历字符串中的每个字符
- 检查字符是否在'a'到'z'范围内
- 使用计数器记录符合条件字符的数量
这种方法的时间复杂度是O(n),其中n是字符串长度,这是最优解,因为必须检查每个字符。
3.3 完整代码实现
cpp复制#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
string s;
while(n--){
cin >> s;
int cnt = 0;
for(int i = 0; i < s.length(); i++){
if(s[i] >= 'a' && s[i] <= 'z'){
cnt++;
}
}
cout << cnt << endl;
}
return 0;
}
3.4 关键技术与注意事项
-
字符范围判断:
- 直接使用字符比较,因为C++中字符本质是ASCII码
- 'a'到'z'在ASCII表中是连续的97到122
-
遍历字符串:
- 使用s.length()获取字符串长度
- 使用下标访问每个字符
-
性能优化:
- 对于非常长的字符串,可以考虑并行处理
- 现代编译器通常会对这种简单循环进行优化
-
常见错误:
- 混淆大小写,错误地统计了大写字母
- 忘记初始化计数器
- 使用错误的循环条件导致越界
注意:在C++中,使用范围for循环(for char c : s)可能更简洁,但在某些竞赛环境中可能不支持C++11特性。
4. 弟弟的作业检查问题
4.1 问题理解与需求分析
这个问题要求我们检查弟弟完成的加减法作业的正确性。题目格式固定为a+b=c或a-b=c,其中:
- a和b是题目给出的不超过100的非负整数
- c是弟弟的答案,可能是数字也可能是"?"(表示不会做)
- 需要统计正确的题目数量
这个问题的难点在于:
- 需要解析格式固定的字符串
- 需要处理特殊情况("?"答案)
- 需要正确提取各部分数字并计算
4.2 解决方案设计
我采用了逐步解析的方法:
- 按顺序读取第一个数字a
- 读取运算符(+或-)
- 读取第二个数字b
- 跳过等号
- 判断是否是"?",如果是则跳过
- 否则读取结果c并进行验证
这种方法直接而有效,充分利用了题目中格式固定的特点。
4.3 完整代码实现
cpp复制#include <bits/stdc++.h>
using namespace std;
int main(){
string s;
int correct = 0;
while(cin >> s){
int i = 0;
// 读取a
int a = 0;
while(isdigit(s[i])){
a = a * 10 + (s[i] - '0');
i++;
}
// 运算符
char op = s[i++];
// 读取b
int b = 0;
while(isdigit(s[i])){
b = b * 10 + (s[i] - '0');
i++;
}
// 跳过 '='
i++;
// 如果是'?'
if(s[i] == '?') continue;
// 读取c
int c = 0;
while(i < s.length() && isdigit(s[i])){
c = c * 10 + (s[i] - '0');
i++;
}
// 判断是否正确
if(op == '+'){
if(a + b == c) correct++;
}else{
if(a - b == c) correct++;
}
}
cout << correct << endl;
return 0;
}
4.4 关键技术与注意事项
-
字符串解析技巧:
- 使用索引i逐步遍历字符串
- 使用isdigit()判断数字字符
- 使用字符减法将数字字符转换为数值
-
特殊情况处理:
- 遇到"?"时直接跳过该题目
- 确保不处理格式错误的输入(题目保证输入合法)
-
算术验证:
- 根据运算符选择加法或减法验证
- 只统计正确的题目数量
-
常见错误:
- 没有正确处理"?"情况
- 运算符判断错误(如把'-'当作'+')
- 数字提取不完整(如漏掉多位数中的某些位)
提示:在实际应用中,应该增加错误处理机制,比如检查字符串格式是否符合预期,避免程序在非法输入时崩溃。
5. 字符串处理技巧总结
通过这三个题目,我们可以总结出一些通用的字符串处理技巧:
-
选择合适的存储类型:
- 当需要保留前导零或进行字符级操作时,优先使用字符串类型
- 纯数值计算且不需要特殊格式时,可以使用数值类型
-
高效遍历与查找:
- 使用标准库提供的字符串操作方法(如substr, find等)
- 对于简单遍历,直接使用下标访问可能更高效
-
复杂字符串解析:
- 对于格式固定的字符串,可以设计逐步解析的算法
- 使用状态机思想处理更复杂的解析场景
-
性能考量:
- 避免不必要的字符串拷贝
- 对于大规模数据处理,考虑使用更高效的算法或并行处理
-
边界条件检查:
- 始终检查字符串长度是否满足预期
- 处理特殊字符和边界情况
在实际开发中,字符串处理往往比这些题目更复杂,但掌握这些基础技能是解决更复杂问题的前提。建议初学者多练习类似的题目,培养对字符串操作的敏感度和熟练度。