当前位置: 首页 > news >正文

算法题 Day6---String类(3)

目录

题7 : 判断字符串是否回文

法一:

法二:

法三:

题8 : 手机

题9 : 口算练习题

注意事项:

函数补充:

to_string  函数 

stoi  函数

总结:


题7 : 判断字符串是否回文

法一:

#include<iostream>
#include<string>
using namespace std;int main()
{string s;cin >> s;size_t left = 0;size_t right = s.size() - 1;while (left < right){if (s[left] == s[right]){left++;right--;}else{cout << "no" << endl;return 0;}}cout << "yes" << endl;
}

过程:

这段代码的思路是通过双指针从两端向中间遍历比较,来判断字符串是否为回文,具体过程如下:

  • 1. 输入与初始化:首先读取输入的字符串 s ,然后定义两个指针 left (初始指向字符串的第一个字符,索引为0)和 right (初始指向字符串的最后一个字符,索引为 s.size() - 1 )。
  • 2. 双指针遍历比较:进入 while 循环,循环条件是 left < right (只要左指针位置在右指针左边,就继续比较)。
  • - 在循环内,比较 s[left] 和 s[right] 是否相等:
  • - 如果相等,说明当前这对字符符合回文要求,将 left 右移一位( left++ ), right 左移一位( right-- ),继续比较下一对字符。
  • - 如果不相等,说明字符串不是回文,直接输出 no 并结束程序( return 0 )。
  • 3. 循环结束与结果输出:当 while 循环正常结束(即 left >= right ),说明所有对应的字符对都相等,字符串是回文,此时输出 yes 。

法二:

#include<iostream>
#include<string>
using namespace std;int main()
{string s;cin >> s;size_t left = 0;size_t right = s.size() - 1;int n = 1;while (left <= right){if (s[left] != s[right]){n = 0;break;}left++;right--;}if (n == 1){cout << "yes" << endl;}else{cout << "no" << endl;}return 0;
}

这段代码的思路是通过双指针从两端向中间遍历,全程检查所有对应字符对,来判断字符串是否为回文,具体过程如下:

  • 1. 输入与初始化:
  • - 读取输入的字符串 s ;
  • - 定义两个指针 left (初始指向字符串第一个字符,索引为 0 )和 right (初始指向字符串最后一个字符,索引为 s.size() - 1 );
  • - 定义变量 n 并初始化为 1 ,用于标记是否为回文( 1 表示是回文, 0 表示不是)。
  • 2. 双指针遍历检查所有字符对:
  • - 进入 while 循环,循环条件是 left <= right (确保遍历到所有需要比较的字符对,包括字符串长度为奇数时中间的单个字符);
  • - 在循环内,比较 s[left] 和 s[right] 是否不相等:
  • - 如果不相等,说明字符串不是回文,将 n 设为 0 ,并通过 break 退出循环;
  • - 如果相等,将 left 右移一位( left++ ), right 左移一位( right-- ),继续比较下一对字符。
  • 3. 根据标记输出结果:
  • - 循环结束后,判断 n 的值:
  • - 若 n == 1 ,说明所有字符对都相等,字符串是回文,输出 yes ;
  • - 若 n == 0 ,说明存在字符对不相等,字符串不是回文,输出 no 。

法三:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;int main()
{string s1;cin >> s1;string s2 = s1;reverse(s2.begin(), s2.end());if (s1 == s2){cout << "yes" << endl;}else{cout << "no" << endl;}return 0;
}

这段代码采用的是“反转对比法”来判断字符串是否为回文,其核心逻辑基于“回文的正序和逆序完全一致”这一特性,具体细节如下:

  • 步骤1:读取原字符串
  • 通过 cin >> s1 获取输入的字符串,例如输入 abcba ,此时 s1 存储为 "abcba" 。
  • 步骤2:复制并反转字符串
  • - 先创建 s2 并赋值为 s1 的副本( string s2 = s1; ),此时 s2 也为 "abcba" ;
  • - 调用标准库函数 reverse ,将 s2 的字符顺序反转。 reverse 的参数是迭代器区间( s2.begin() 到 s2.end() ),作用是交换区间内的字符顺序。执行后, s2 变为 "abcba" 的逆序,即 "abcba" (因为原字符串本身是回文)。
  • 步骤3:比较原字符串与反转后的字符串
  • 通过 if (s1 == s2) 判断两者是否完全相同:
  • - 若相同(如上述例子),说明原字符串是回文,输出 yes ;
  • - 若不同(例如输入 abcd ,反转后为 dcba ,与原字符串不等),说明不是回文,输出 no 。

 注意事项:

  • string 类本身没有提供名为 reverse 的成员函数,我们代码中用的 reverse 是C++标准库的通用算法函数,而非 string 的成员,因此必须包含 <algorithm> 头文件才能使用。
  • 当需要保留原始数据的副本时,或者在后续的操作中可能需要参考原始数据,先拷贝一份可以避免原始数据被覆盖或修改。
  •  reverse  是原地操作函数。它的工作方式是直接修改传入的容器/数据结构本身(通过迭代器指定的区间),不会创建新的副本。例如对字符串  s1  调用  reverse(s1.begin(), s1.end())  后, s1  自身的字符顺序会被直接反转,原有的字符排列会被覆盖,整个过程不会额外生成新的字符串对象。

补充:

好的,结合“直接在原对象上修改、无需复制到新对象”的核心标准,以下是 C++ 中符合该要求的常用函数分类汇总,涵盖字符串、容器、通用算法等场景,每个类别下明确函数作用和修改特点:


一、字符串类( std::string )专属成员函数
所有函数均直接操作调用者( string  对象),修改后原对象的内容/长度/容量直接变化,无需生成新  string  对象。

  • insert :在指定位置插入字符、字符串或迭代器区间内容,直接扩展原字符串长度并修改内容。
  • erase :删除指定位置的单个字符,或指定迭代器区间内的字符,直接缩短原字符串长度并修改内容。
  • append :在原字符串末尾追加字符、字符串或迭代器区间内容,直接扩展原字符串长度。
  • assign :用新内容(字符、字符串、迭代器区间或重复字符)完全替换原字符串内容,原对象直接被覆盖。
  • replace :替换原字符串中指定位置/迭代器区间的内容(替换为字符、字符串或迭代器区间),直接修改原对象(长度可能增/减/不变)。
  • pop_back :删除原字符串的最后一个字符,直接缩短长度(需确保字符串非空)。
  • push_back :在原字符串末尾添加一个字符,直接扩展长度。
  • resize :调整原字符串的长度——若新长度大于原长度,用指定字符(默认空字符)补全;若小于原长度,截断末尾字符,直接修改原对象长度和内容。
  • swap (成员版):与另一个  string  对象交换内容、长度和容量,两个原对象均被直接修改(无额外内存拷贝,效率高)。
  • clear :清空原字符串所有内容,使原对象变为空字符串(长度归 0,容量可能保留)。

二、序列式容器(以  std::vector 、 std::list 、 std::deque  为例)成员函数
 
容器对象调用这些函数后,自身的元素、大小( size )甚至容量( capacity )直接变化,无需生成新容器对象。
 
1. 通用操作(多容器支持)

  • push_back :在容器末尾添加一个元素( vector / deque / list  均支持),直接增加容器大小; vector  若容量不足会自动扩容,但仍修改原对象。
  • pop_back :删除容器末尾的一个元素( vector / deque / list  均支持),直接减小容器大小,不影响原对象其他元素的存储地址( list  无地址概念)。
  • erase :删除指定位置的单个元素,或指定迭代器区间内的元素( vector / deque / list  均支持),直接减小容器大小; vector / deque  会移动后续元素填补空位, list  直接调整节点指针。
  • insert :在指定位置插入单个元素、多个相同元素或迭代器区间内容( vector / deque / list  均支持),直接增加容器大小; vector  若容量不足会扩容, list  仅需调整节点指针。
  • resize :调整容器大小( vector / deque / list  均支持)——新大小大于原大小时,用默认构造或指定的元素补全;新大小小于原大小时,截断末尾元素,直接修改原容器的元素数量。
  • clear :清空容器内所有元素( vector / deque / list  均支持),使容器大小归 0; vector  容量可能保留, list  会释放节点内存,但均不改变原容器对象本身。
  • swap (成员版):与另一个同类型容器交换所有元素、大小和容量( vector / deque / list  均支持),两个原容器均被直接修改,无元素拷贝(仅交换内部指针/状态)。

2. 特定容器专属操作

  • std::list  专属:
  • push_front / pop_front :在链表头部添加/删除元素,直接修改原链表大小( vector  不支持)。
  • sort (成员函数):直接对原链表元素排序(无需像  vector  那样依赖  std::sort ),排序后原链表结构直接变化。
  • reverse (成员函数):反转原链表中元素的顺序,直接修改原链表结构。
  • std::deque  专属:
  • push_front / pop_front :在双端队列头部添加/删除元素,直接修改原队列大小( vector  不支持)。

三、通用算法( <algorithm>  头文件,需作用于容器迭代器)
 
这些算法通过迭代器直接操作容器内的元素,修改结果直接体现在原容器中,无需生成新容器。

  • std::reverse :反转指定迭代器区间内的元素顺序(支持  vector / string / list  等),原容器/字符串的元素顺序直接变化。
  • std::sort :对指定迭代器区间内的元素排序(支持  vector / deque  等随机访问容器, list  需用自身成员  sort ),原容器的元素顺序直接按规则重组。
  • std::fill :将指定迭代器区间内的所有元素赋值为同一个指定值(支持所有容器),原容器内对应位置的元素直接被覆盖。
  • std::fill_n :从指定起始迭代器开始,连续填充  n  个元素为指定值,直接修改原容器的  n  个元素。
  • std::replace :在指定迭代器区间内,将所有等于“旧值”的元素替换为“新值”(支持所有容器),原容器内匹配的元素直接被修改。
  • std::replace_if :在指定迭代器区间内,将所有满足“判断函数”的元素替换为“新值”,原容器内符合条件的元素直接被修改。
  • std::generate :用指定的“生成函数”(无参数,返回值为元素类型)生成值,填充指定迭代器区间,原容器内对应元素直接被生成的值覆盖。
  • std::generate_n :从指定起始迭代器开始,用生成函数生成  n  个值并填充,直接修改原容器的  n  个元素。
  • std::rotate :将指定迭代器区间  [first, last)  内的元素,以“中间迭代器  middle ”为分界,循环旋转(例如  [1,2,3,4]  以  3  为分界,旋转后为  [3,4,1,2] ),原容器元素顺序直接变化。
  • -std::remove / std::remove_if :在指定迭代器区间内,将等于“指定值”( remove )或满足“判断函数”( remove_if )的元素移到区间末尾,返回指向“新末尾”的迭代器;原容器的大小未变,但前半部分(有效元素)直接被调整,需配合容器的  erase  才能彻底删除末尾无效元素(本质仍是对原容器的修改)。std::unique :在指定迭代器区间内,移除相邻的重复元素(仅保留第一个),将重复元素移到区间末尾,返回新末尾迭代器;原容器大小未变,有效元素部分直接被调整,需配合  erase  彻底删除重复元素(修改作用于原容器)。

核心共性总结
以上所有函数均满足“操作直接作用于原对象,修改结果实时体现在原对象上,无需创建新对象来存储修改后的内容”——无论是字符串的长度变化、容器的元素增减,还是元素值/顺序的调整,最终都无需通过“原对象 → 新对象”的复制过程,原对象本身就是修改的载体。

题8 : 手机

代码:

#include<iostream>
#include<string>
using namespace std;int count[26] = { 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4 };int main()
{int n = 0;string s;getline(cin, s);for (auto ch : s){if (ch == ' '){n += 1;}else{n += count[ch - 'a'];}}cout << n << endl;return 0;
}

思路:这段代码是为了解决“计算手机九宫格键盘输入字符串的总按键次数”的问题,以下是详细分析:
 
1. 问题背景(结合题目)
手机九宫格键盘的字符分布如下:
- 2键: abc (按1次出 a ,2次出 b ,3次出 c )
- 3键: def (同理1/2/3次)
- 4键: ghi (1/2/3次)
- 5键: jkl (1/2/3次)
- 6键: mno (1/2/3次)
- 7键: pqrs (1/2/3/4次)
- 8键: tuv (1/2/3次)
- 9键: wxyz (1/2/3/4次)
- 0键:按1次出空格
我们需要统计输入字符串中每个字符(含空格)对应的按键次数,最后求和。
 
2. 代码逐部分解析
 (1) count 数组初始化

int count[26] = { 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4 };

 - 数组长度为26,对应26个小写英文字母 a-z 。
- 每个元素的值表示该字母在九宫格键盘上的按键次数。例如:
-  count[0] ( a )= 1(2键按1次)
-  count[18] ( s )= 4(7键按4次)
-  count[25] ( z )= 4(9键按4次)
 
(2)主函数逻辑

int main()
{int n = 0;  // 总按键次数累加器,初始为0string s;   // 存储输入的字符串getline(cin, s);  // 读取整行输入(包含空格)for (auto ch : s)  // 遍历字符串中的每个字符{if (ch == ' ')  // 如果是空格{n += 1;  // 空格对应0键按1次,次数+1}else  // 如果是字母{// ch - 'a' 计算字母在字母表中的索引(a→0,b→1,…,z→25)// 从count数组中取出对应按键次数,累加到nn += count[ch - 'a'];}}cout << n << endl;  // 输出总按键次数return 0;
}

综上,这段代码通过预存每个字母的按键次数,遍历输入字符串并累加,高效地解决了手机键盘按键次数统计的问题。

题9 : 口算练习题

代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{int i = 0;cin >> i;string op;//操作符string last;//记录上一次的运算类型while (i--){//输入数据int n1, n2;int r;  //计算的结果string ans;//拼接完整算式cin >>op; //均为单个字符 : a b c 275if (op == "a" || op == "b" || op == "c"){cin >> n1 >> n2;ans += to_string(n1);if (op == "a"){r = n1 + n2;ans += "+";ans += to_string(n2);ans += "=";ans += to_string(r);}else if (op == "b"){r = n1 - n2;ans += "-";ans += to_string(n2);ans += "=";ans += to_string(r);}else{r = n1 * n2;ans += "*";ans += to_string(n2);ans += "=";ans += to_string(r);}last = op;}else//这一行有两个数据,执行上一次的运算{n1 = stoi(op);ans += to_string(n1);cin >> n2;if (last == "a"){r = n1 + n2;ans += "+";ans += to_string(n2);ans += "=";ans += to_string(r);}else if (last == "b"){r = n1 - n2;ans += "-";ans += to_string(n2);ans += "=";ans += to_string(r);}else{r = n1 * n2;ans += "*";ans += to_string(n2);ans += "=";ans += to_string(r);}}cout << ans << endl;cout << ans.size() << endl;}return 0;
}

要解决这道“口算练习题”问题,我们可以从需求分析和代码逻辑两方面来拆解推导思路:
 
推导思路:如何想到这种方法?

  • 1. 理解问题本质:题目要求处理两种输入格式的算式——“三个数据(含运算类型)”或“两个数据(继承上一次运算类型)”,并输出完整算式和长度。核心是记录运算类型的状态,并对不同输入格式做分支处理。
  • 2. 状态管理需求:由于存在“继承上一次运算类型”的情况,需要一个变量(如 last )来存储上一次的运算类型( a / b / c )。
  • 3. 字符串拼接需求:要输出完整算式(如 5+8=13 ),需要将数字、运算符、结果拼接成字符串,因此用 string 类型的 ans 来动态构建算式。
  • 4. 分支逻辑设计:根据输入的“运算类型是否存在”(即一行是三个数据还是两个数据),分两种大情况处理,每种情况再根据运算类型( a / b / c )细分小分支。

代码过程逻辑详解:
 
以下结合代码逐行解析逻辑: 
步骤拆解

  • 1. 输入总数量 i :先读取需要处理的算式总数 i ,通过 while(i--) 循环处理每个算式。
  • 2. 初始化变量: op 存储当前行的第一个输入(可能是运算类型或第一个数), last 存储上一次的运算类型, ans 拼接完整算式, n1 / n2 存储运算数, r 存储结果。
  • 3. 分支1:三个数据的情况:
  • 若 op 是 "a" / "b" / "c" ,说明当前行有三个数据(运算类型+两个数)
  • 读取 n1 和 n2 ,根据 op 的类型( a 加、 b 减、 c 乘)计算 r ,并拼接成 “n1+/-/*n2=r” 的字符串 ans 。
  • 用 last 记录当前 op ,供后续“两个数据”的情况使用。
  • 4. 分支2:两个数据的情况:
  • 若 op 不是 "a" / "b" / "c" ,说明当前行只有两个数据(继承上一次运算类型)。
  • 将 op 转为整数 n1 ,读取 n2 ,根据 last 的类型计算 r ,同样拼接成 “n1+/-/*n2=r” 的字符串 ans 。
  • 5. 输出结果:每个算式处理完成后,输出 ans (完整算式)和 ans.size() (算式长度)。

这种方法的核心是通过 last 变量维护运算类型的状态,并利用 string 的拼接能力构建完整算式,从而高效处理两种输入格式的分支逻辑,完全贴合题目的需求。

注意事项:

在 C++ 中, std::string  本质上是对字符数组的封装(内部通过字符数组存储字符串,以  '\0'  结尾)。正因为它是“字符数组”的逻辑,所以:

  • 当表示字符串字面量(用于初始化  string  或与  string  比较)时,必须用双引号(如  "a" 、 "abc" )—— 因为双引号表示的是“字符数组”(即使只有一个字符,也是长度为2的数组: 'a' + '\0' )。
  • 单引号表示单个字符字面量(如  'a' ),它的类型是  char ,和  string (字符数组的封装)是不同的类型,因此不能直接用于  string  的初始化或比较。

简单来说: string  是“字符数组的封装”,所以表示它的字面量必须用双引号;单引号是单个  char ,和  string  类型不兼容。

函数补充:

to_string  和  stoi  是 C++ 标准库中用于字符串与数值类型转换的关键函数,以下是详细介绍:

to_string  函数 

  • 功能:将数值类型(如  int 、 double  等)转换为  std::string  类型的字符串。
  • 头文件: <string> 
  • 使用场景:在本题中,用于将运算数( n1 、 n2 )和运算结果( r )转换为字符串,以便拼接成完整的算式(如  “5+8=13” )。

示例:

int num = 123;
string s = to_string(num);  // s 的值为 "123"

stoi  函数

  • 功能:将  std::string  类型的字符串转换为  int  类型的整数。
  • 头文件: <string> 
  • 使用场景:在本题中,当输入行只有两个数据时,第一个数据是字符串形式的数字(如输入  “5” ),需要用  stoi  将其转换为  int  类型的运算数( n1 )。

示例:

string s = "456";
int num = stoi(s);  // num 的值为 456

补充:类似的转换函数
C++ 标准库中还有一系列用于字符串与数值转换的函数,覆盖不同数值类型:

  • stof :字符串转  float 
  • stod :字符串转  double 
  • stol :字符串转  long 
  • stoll :字符串转  long long 
  • 反向转换(数值转字符串):除了  to_string ,还可以用字符串流( stringstream )实现更灵活的转换,但  to_string  是最直接的方式。

在本题的代码中,这两个函数的配合使用,完美解决了“数值与字符串拼接”的需求——既可

以将数字转成字符串来构建算式,也可以将输入的字符串数字转成整数来参与运算。

总结:

  1. 回文判断的三种方法:双指针法(两端向中间遍历)、标记法(全程检查字符)和反转对比法(比较原字符串与反转字符串)。

  2. 手机按键次数统计:通过预存字母按键次数的数组,累加输入字符串中各字符对应的按键次数(包括空格处理)。

  3. 口算练习题处理:使用状态变量记录上一次运算类型,处理两种输入格式(三数据和两数据),利用字符串拼接生成完整算式并计算长度。

代码特点:

  • 回文判断:强调原地操作和状态维护
  • 手机按键:使用数组映射提高效率
  • 口算题:结合字符串转换和条件分支处理多种输入情况

文章还补充了C++中字符串与数值转换函数(to_string、stoi)的使用说明。

感谢大家的观看


文章转载自:

http://BOD3GtTP.chkfp.cn
http://mtvag6AB.chkfp.cn
http://5th2RPG8.chkfp.cn
http://BUaqu7HE.chkfp.cn
http://pH0RGaIW.chkfp.cn
http://juJ6tcg8.chkfp.cn
http://4u217CKk.chkfp.cn
http://9Vp78BlN.chkfp.cn
http://gatGkKah.chkfp.cn
http://P3PMMTc2.chkfp.cn
http://PRbpuHKy.chkfp.cn
http://AgY1nmiM.chkfp.cn
http://tbaHINYH.chkfp.cn
http://1PE0H7pm.chkfp.cn
http://7Tqzgp3x.chkfp.cn
http://OtDnQU6v.chkfp.cn
http://fsGnVwqL.chkfp.cn
http://8upbLRSn.chkfp.cn
http://UosmWlkc.chkfp.cn
http://gJ4vyfRN.chkfp.cn
http://ADfKto2W.chkfp.cn
http://AsMGEfzz.chkfp.cn
http://748jkuk1.chkfp.cn
http://bAZAvxRf.chkfp.cn
http://eTWFVbqP.chkfp.cn
http://QGbUwsTJ.chkfp.cn
http://fnHwlHv9.chkfp.cn
http://7Y9UgrLv.chkfp.cn
http://4gBQG5yI.chkfp.cn
http://1V7iVFvy.chkfp.cn
http://www.dtcms.com/a/381284.html

相关文章:

  • 知识模型中优化和模拟决策内容有哪些
  • PRINCE2与PMP项目管理体系对比
  • LINUX中USB驱动架构—设备驱动
  • 数据驱动工业智能决策:从痛点破局到全局优化的技术实践与方法论
  • 射频EVM
  • 21.2 Alpaca指令微调实战:Dolly-15K数据增强让LLaMA-2效果飙升82%
  • 每周资讯 | B站新游《三国:百将牌》首曝;2025年移动游戏市场预计达到1030亿美元
  • VMware网络配置
  • fastapi微服务
  • DNS解析:递归查询与迭代查询详解
  • 中级统计师-统计法规-第五章 统计机构与统计人员
  • API 资产治理:ETag/Cache-Control/分页/排序/投影的“契约基线”
  • V少JS基础班之第八弹:this
  • Class52 双向循环神经网络
  • STM32HAL库_cubeMX
  • Class54 编码器-解码器
  • c++多设备并发运行且互相操作 上位机软件结构
  • PCDN双跑量系统
  • Altium Designer使用精通教程 第三章(原理图绘制及编译检查)
  • Docker技术解析
  • MySQL数据库(一)—— 数据库基础与MySQL安装管理指南
  • 京东商品详情 API 全解析:合规对接与 B2C 场景实战指南
  • 高德地图从零开始:Key 申请到项目初始化全流程教程(Vue3 + AMap 2.0)
  • 从跟跑到领跑:OBOO鸥柏触摸屏的军用信息化技术自主之路
  • LLM(三)
  • u盘 修复
  • C++异常处理设计与实践:主动抛出异常的处理策略
  • 嵌入式数据结构笔记三——单向链表Ⅲ
  • Ampace厦门新能安校招/社招Verify测评演绎数字推理行测真题题库及远程助攻
  • ORM框架SQLAlchemy工具:模型类(Model Class)和实体类(Entity Class)介绍