算法题 Day5---String类
题一 : 标题统计
这道题有多种解题方法:
法一 : getline(cin,s)法
1.范围for遍历法
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main()
{string s;getline(cin ,s);int count = 0;for(auto ch : s){ if(!isspace(ch)){count++;}/*if(isspace(ch)){continue;}else{count++;}*/} cout<<count<<endl;return 0;
}
补充 : isspace函数
isspace 是C/C++标准库中用于判断字符是否为空白字符的函数,定义在 <cctype> (C++)或 <ctype.h> (C)头文件中。(一定要包含头文件)
int isspace(int c);
- - 参数 c :需要判断的字符(以 int 类型传入,实际是字符的ASCII码值)。
- - 返回值:若 c 是空白字符,返回非0值(通常为 true 的等效值);否则返回0( false )。
判断一个字符是否属于以下空白字符类别:
- - 空格( ' ' )
- - 换行符( '\n' )
- - 制表符( '\t' )
- - 回车符( '\r' )
- - 垂直制表符( '\v' )
- - 换页符( '\f' )
2.下标法遍历法
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main()
{string s;getline(cin ,s);int sz = s.szie();int count = 0;for(int i=0;i<sz;i++){if(!isspace(s[i])){count++;}} return 0;
}
3.迭代器遍历法
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main()
{string s;getline(cin ,s);int count = 0;for(string::iterator it = s.begin();it!=s.end();++it){if(!isspace(*it)){count++;}} cout<<count<<endl;return 0;
}
法二 : while(cin>>s)法
#include<iostream>
#include<string>
using namespace std;
int main()
{string s;int count = 0; while(cin>>s) //ctrl+z 结束循环{count+=s.size();}cout<<count<<endl;return 0;
}
- 有时候处理⼀个字符串的时候,也不⼀定要⼀次性读取完整个字符串,如果字符串中有空格 的话,其实可以当做多个单词,⼀次读取。
- cin >> s 会返回⼀个流对象的引⽤,即 cin 本⾝。在 C++ 中,流对象(如 cin )可 以被⽤作布尔值来检查流的状态。如果流的状态良好(即没有发⽣错误),流对象的布尔值 为 true 。如果发⽣错误(如遇到输⼊结束符或类型不匹配),布尔值为 false 。
- 在 while (cin >> s) 语句中,循环的条件部分检查 cin 流的状态。如果流成功读取 到⼀个值, cin >> s 返回的流对象 cin 将被转换为 true ,循环将继续。如果读取失败(例如遇到输⼊结束符或无法读取到⼀个值), cin >> s 返回的流对象 cin 将被转换 为 false ,循环将停⽌。
题二 : 石头剪刀布
解题思路:
解题方法:
#include<iostream>
using namespace std;
int main()
{int n;cin>>n;while(n--){string s1,s2;cin>>s1>>s2;if(s1==s2){cout<<"Tie"<<endl;}else if(s1 == "Rock" && s2=="Scissors"){cout<<"Player1"<<endl;}else if(s1 == "Scissors" && s2=="Paper"){cout<<"Player1"<<endl;}else if(s1 == "Paper" && s2=="Rock"){cout<<"Player1"<<endl;}elsecout<<"Player2"<<endl;}return 0;
}
1. 输入处理:首先读取整数 n ,表示游戏的次数。
2. 循环判断:通过 while(n--) 循环 n 次,每次循环中读取两个字符串 s1 (Player1的选择)和 s2 (Player2的选择)。
3. 胜负判定:
- 若 s1 和 s2 相等,判定为平局,输出 Tie 。
- 若满足“石头打剪刀”( s1="Rock" 且 s2="Scissors" )、“剪刀剪布”( s1="Scissors" 且 s2="Paper" )、“布包石头”( s1="Paper" 且 s2="Rock" )这三种情况之一,Player1获胜,输出 Player1 。
- 其余情况则Player2获胜,输出 Player2 。
- 在这段代码中使用 && (逻辑与运算符),是因为需要同时满足两个条件才能判定 Player1 获胜。
以 if (s1 == "Rock" && s2 == "Scissors") 为例:只有当 s1 是 “Rock”并且 s2 是 “Scissors” 时,这个条件才成立,此时 Player1 获胜。如果只用单个条件(比如只判断 s1 == "Rock" ),就无法准确区分胜负逻辑,会导致判断错误。
简单来说, && 在这里的作用是确保两个条件同时满足,从而精准匹配“石头赢剪刀”这类胜负规则。
题三 : 密码翻译
解题思路:
法一 : 下标遍历
#include <iostream>
#include <string>using namespace std;int main()
{string s;//输入getline(cin, s);//遍历字符串int i = 0;for(i = 0; i < s.size(); i++){if((s[i] >= 'b' && s[i] <= 'z') || (s[i] >= 'B' && s[i] <= 'Z'))s[i] -= 1;else if(s[i] == 'a')s[i] = 'z';else if(s[i] == 'A')s[i] = 'Z';} cout << s << endl;return 0;
}
法二 : 迭代器遍历
#include <iostream>
#include <string>
using namespace std;int main()
{string s;getline(cin, s);// 定义迭代器,从字符串起始位置开始遍历for (string::iterator it = s.begin(); it != s.end(); ++it){if ((*it >= 'b' && *it <= 'z') || (*it >= 'B' && *it <= 'Z')){*it -= 1; // 字母减1(如b→a,B→A)}else if (*it == 'a'){*it = 'z'; // a→z}else if (*it == 'A'){*it = 'Z'; // A→Z}// 其余字符保持不变}cout << s << endl;return 0;
}
那用范围for遍历可以吗:
答案是不可以的
在这三种遍历字符串的方式中,下标遍历和迭代器遍历可以修改原字符串,而范围for循环不可以。
- 对于下标遍历,我们通过 s[i] 直接访问原字符串中索引为 i 的字符,对 s[i] 的修改会直接作用于原字符串的实际存储位置。
- 迭代器遍历中,迭代器解引用后( *it )直接指向原字符串的字符,修改 *it 就是在修改原字符串的内容。
- 而范围for循环里,循环变量 ch 是原字符的拷贝,属于值传递,修改 ch 只是改变了这个临时拷贝变量,并不会对原字符串产生影响。
但是我们可以在范围for循环中给循环变量加上引用( auto& ),就能直接修改原字符串,这是让范围for循环支持修改操作的关键。
具体来说:
1. 不加引用( auto ch : s ): ch 是原字符串字符的拷贝,修改 ch 只改变临时变量,与原字符串无关,所以无法修改原内容。
2. 加引用( auto& ch : s ): ch 成为原字符串字符的引用(相当于给原字符起了“别名”),对 ch 的修改会直接作用于原字符串的对应字符,因此能实现修改效果。
法三 : 加引用的范围for
#include <iostream>
#include <string>
using namespace std;int main() {string s;getline(cin, s);// 加引用auto&,使ch指向原字符串的字符for (auto& ch : s) {if ((ch >= 'b' && ch <= 'z') || (ch >= 'B' && ch <= 'Z')) {ch -= 1;} else if (ch == 'a') {ch = 'z';} else if (ch == 'A') {ch = 'Z';}}cout << s << endl;return 0;
}
- 不加引用( auto ch : s ): ch 是原字符串字符的拷贝,修改 ch 只改变临时变量,与原字符串无关,所以无法修改原内容。
- 加引用( auto& ch : s ): ch 成为原字符串字符的引用(相当于给原字符起了“别名”),对 ch 的修改会直接作用于原字符串的对应字符,因此能实现修改效果。