算法题 Day5---String类(2)
题四 : 文字处理软件
代码:
#include<iostream>
#include<string>using namespace std;
int main()
{string str; //被操作的字符串int q = 0;int m = 0;cin >> q;string s;cin >> s; //原始字符串int a, b; while (q--){//处理一次操作cin >> m;switch (m){case 1:cin >> str;s += str;cout << s << endl;break;case 2:cin >> a >> b;s = s.substr(a, b);cout << s << endl;break;case 3:cin >> a >> str;s.insert(a, str);cout << s << endl;break;case 4:cin >> str;size_t n = s.find(str);if (n == string::npos){cout << -1 << endl;}elsecout << n << endl;break;}}return 0;
}
分析:
输入部分:首先输入操作次数 q ,再输入初始字符串 s 。
循环处理操作:通过 while(q--) 循环处理 q 次操作,每次操作根据输入的 m (操作类型)执行不同的功能:
- 操作1( case 1 ):输入字符串 str ,将其追加到原始字符串 s 后面,然后输出当前的 s 。
- 操作2( case 2 ):输入整数 a 和 b ,截取 s 中从第 a 个字符开始的 b 个字符,并将 s 更新为该子串,随后输出 s 。
- 操作3( case 3 ):输入整数 a 和字符串 str ,在 s 的第 a 个字符前插入 str ,再输出更新后的 s 。
- 操作4( case 4 ):输入字符串 str ,查找 str 在 s 中最先出现的位置,若找不到则输出 -1 ,找到则输出其位置。
最后程序正常结束,返回 0 。
注意事项:
- switch-case语句的正确书写:case+空格+数字,break
- 正确的输入顺序
- 会了解和使用string中的成员函数 : find substr insert npos
- npos 的核心作用就是标识“查找失败”的状态,让程序能区分“找到子串”和“未找到子串”两种情况,从而输出对应的结果(未找到则输出 -1 ,找到则输出位置索引)。
题五 : 单词的长度
法一:
#include<iostream>
#include<string>using namespace std;
int main()
{string s;bool flag = true;while (cin >> s){if (flag){cout << s.size();flag = false;}else{size_t n = s.size();cout << "," << n;}}return 0;
}
法二:
#include<iostream>
#include<string>using namespace std;
int main()
{string s;cin >> s;cout << s.size();while (cin >> s){size_t n = s.size();cout << "," << n;}return 0;
}
注意事项:
注意读题
学会用while(cin>>s)逐个读取单词
- 有时候处理⼀个字符串的时候,也不⼀定要⼀次性读取完整个字符串,如果字符串中有空格 的话,其实可以当做多个单词,⼀次读取。
- cin >> s 会返回⼀个流对象的引⽤,即 cin 本⾝。在 C++ 中,流对象(如 cin )可 以被⽤作布尔值来检查流的状态。如果流的状态良好(即没有发⽣错误),流对象的布尔值 为 true 。如果发⽣错误(如遇到输⼊结束符或类型不匹配),布尔值为 false 。
- 在 while (cin >> s) 语句中,循环的条件部分检查 cin 流的状态。如果流成功读取 到⼀个值, cin >> s 返回的流对象 cin 将被转换为 true ,循环将继续。如果读取失败(例如遇到输⼊结束符或无法读取到⼀个值), cin >> s 返回的流对象 cin 将被转换 为 false ,循环将停⽌。
题三 : 单词反转
法一:双指针法
#include<iostream>
#include<string>using namespace std;
int main()
{string s;while (cin >> s){//反转单词int left = 0;int right = s.size()-1;while (left < right){char tmp = s[left]; //左给tmps[left] = s[right]; //右给左s[right] = tmp; //tmp给右left++;right--;}cout << s << endl;}return 0;
}
法二:reserve法
#include<iostream>
#include<string>using namespace std;
int main()
{string s;while (cin >> s){reverse(s.begin(), s.end());cout << s << endl;}return 0;
}
补充---原地操作函数
在 C++ 中,“原地操作”的核心是直接修改原始对象的内存数据,而不是创建新对象来存储结果。这一设计主要是为了提高效率(减少内存分配和拷贝的开销),同时让代码逻辑更直观。许多作用于容器(如 string 、 vector 、 array 等)的函数/方法都是原地操作,核心特点是直接修改原始对象,不创建新对象存储结果。以下是常见类别及示例:
1. 字符串( string )类的原地操作方法
除了之前提到的 insert , reverse 还有多个原地修改方法:
- erase :删除字符串中的指定字符/子串,直接修改原字符串。
示例: s.erase(2, 3); (删除从索引2开始的3个字符)。
- replace :替换字符串中的指定子串,直接更新原字符串。
示例: s.replace(1, 2, "xy"); (将索引1开始的2个字符替换为"xy")。
- append :在字符串末尾追加内容,直接修改原字符串(和 += 功能类似)。
示例: s.append("123"); (原字符串后加"123")。
- pop_back :删除字符串的最后一个字符,直接修改原字符串。
示例: s.pop_back(); (删除 s 的最后一个字符)。
2. <algorithm> 头文件中的原地操作算法
这类算法需包含 <algorithm> 头文件,作用于容器的迭代器范围,直接修改原始容器:
- sort :对容器元素进行原地排序(默认升序)。
示例: sort(v.begin(), v.end()); (对 vector<int> v 原地排序)。
- unique :移除容器中连续的重复元素(需先排序,仅保留第一个),直接修改原容器。
示例: v.erase(unique(v.begin(), v.end()), v.end()); (配合 erase 实现去重)。
- fill :将容器指定范围的元素填充为某个值,直接覆盖原数据。
示例: fill(v.begin(), v.end(), 0); (将 vector<int> v 所有元素设为0)。
- swap_ranges :交换两个容器指定范围的元素,直接修改两个原始容器。
示例: swap_ranges(v1.begin(), v1.end(), v2.begin()); (交换 v1 和 v2 的元素)。
3. 向量( vector )类的原地操作方法
vector 作为动态数组,多数修改方法也是原地操作:
- push_back :在 vector 末尾添加元素,直接扩展原容器(可能触发内存重新分配,但仍属于原地修改)。
示例: v.push_back(5); (给 vector<int> v 末尾加5)。
- -pop_back :删除 vector 的最后一个元素,直接修改原容器。
示例: v.pop_back(); (删除 v 的最后一个元素)。
- erase :删除 vector 中指定位置/范围的元素,直接修改原容器。
示例: v.erase(v.begin() + 2); (删除 v 索引2处的元素)。
- -resize :调整 vector 的大小,若扩容则填充默认值(或指定值),直接修改原容器。
示例: v.resize(10, 2); (将 v 大小设为10,新增元素填2)。
这些函数/方法的共同特点是:操作后原始对象的内容被直接修改,无需赋值给新变量(赋值也只是复用原对象的引用,不会产生新对象)。