c++ - 关于 string 的练习题
目录
前言
1、题1 仅仅反转字母:
解法一:遍历+swap
参考代码1:
参考代码2:
2、题2 . 字符串中的第一个唯一字符:
解法一:暴力解法
解法二:计数排序(哈希)
参考代码:
3、题3 字符串相加:
参考代码:
4、题4 字符串最后一个单词的长度:
参考代码:
总结
前言
路漫漫其修远兮,吾将上下而求索;
大家可以自己先尝试做一下喔~
917. 仅仅反转字母 - 力扣(LeetCode)
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
415. 字符串相加 - 力扣(LeetCode)
字符串最后一个单词的长度_牛客题霸_牛客网
1、题1 仅仅反转字母:
917. 仅仅反转字母 - 力扣(LeetCode)
用string 中的接口来实现的话,基本上就是遍历 + 修改;
解法一:遍历+swap
标准库中实现了”交换“这一函数模板;
设置两个指针,让这两个指针分别找到两端的英文字母,然后进行交换;整体的逻辑有点像hoare 版本的快速排序;
参考代码1:
//判断当前字符是否为英文字符bool isLetter(char ch){if((ch >= 'a' && ch <= 'z' )|| (ch >='A' && ch <= 'Z')) return true;else return false;}string reverseOnlyLetters(string s) {//遍历 + swapint left = 0, right = s.size();while(left < right){//让left 从左往右找到英文字母while(left<right && !isLetter(s[left])){left++;}//让right 从右往左找英文字母while(left < right && !isLetter(s[right])){right--;}//如果都找到了并且没有越界就进行交换if(left<right){swap(s[left++] ,s[right--]);}}return s;}
判断一个字符是不是英文字母,还有一个现成的接口函数:isalpha
参考代码2:
string reverseOnlyLetters(string s) {//遍历 + swapint left = 0, right = s.size();while(left < right){//让left 从左往右找到英文字母while(left<right && !isalpha(s[left])){left++;}//让right 从右往左找英文字母while(left < right && !isalpha(s[right])){right--;}//如果都找到了并且没有越界就进行交换if(left<right){swap(s[left++] ,s[right--]);}}return s;}
2、题2 . 字符串中的第一个唯一字符:
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
解法一:暴力解法
将每一个字符均与其他字符按顺序比较一遍,如果没有相等的便是第一个不重复的字符;
解法二:计数排序(哈希)
倘若有一堆数,而这些数的范围比较集中,那么此时就可以统计这些数据出现的次数,然后再去排序;在本题之中,可以利用”统计次数“的思想,由于本题中只包含小写字母,于是可以开辟一个大小为26 的数组来统计整个字符串中字符出现的次数,然后再一次按照字符串s 中字符的顺序遍历并查找计数数组中该字符出现的次数,如果为1直接返回就行,没有找到就返回 -1;本质上就是哈希的思想;
参考代码:
int firstUniqChar(string s) {int count[26] = {0};for(auto ch : s) count[ch-'a']++;//统计、映射for(size_t i = 0;i<s.size();++i){if(count[s[i]-'a'] == 1) return i; }return -1;//没有找到}
3、题3 字符串相加:
415. 字符串相加 - 力扣(LeetCode)
本题是典型的大数相加;
当数据过大的时候,普通整形没有办法进行准确的表示;而CPU有直接的运算能力也只能为 0~8byte 范围内的;对于大数,可以用字符串来存档;
在C语言中有两个接口函数:atoi(将字符串转换成整型), itoa(将整型转换成字符串);
在C++之中也有两个相似功能的函数:stoi 、to_string;
- stoi: 给string 对象便可以将其转换成对应的整型
- to_string : 将整型家族中的数据转换成对应的字符串
用以上的接口函数来实现是行不通的,用字符串来存储一个数据可以很长,超出整形家族中可存储的数据范围,而存在溢出的风险;
正确思想:利用字符串来实现加法的运算思想,并实现进位;
首先第一步是取两个字符串的最后一个字符(不能直接相加,因为字符进行运算 '+' 以ASCII码值的形式去计算);然后是将获取到的字符转换成整型,然后再计算;最后是处理进位,需要利用一个变量来记录进位的信息,下一次相加的时候再加上即可;
还需要注意的是,当较短的字符串计算完了之后,不能直接将较长字符串剩余的字符拷贝下来,因为还有可能存在多次进位的情况;eg. 999999999 + 10;
而每次得到的每一位数字,需要在目标字符串中进行头插或者尾插+旋转字符串;其中头插的效率十分低下,因为每头插一个数据仅需要挪动数据;所以此处采用尾插+旋转字符串;
参考代码:
string addStrings(string num1, string num2) {//获取两个字符串最后一个字符string str;int end1 = num1.size()-1, end2 = num2.size()-1;//进位int next = 0;while(end1 >=0 || end2>=0){int x1 = end1 >= 0 ? num1[end1--] -'0' : 0;int x2 = end2 >= 0 ? num2[end2--] - '0' : 0;int ret = x1 + x2 + next;next = ret / 10;//获取进位的信息ret = ret % 10;//获取余数//尾插str += ('0' + ret);}//有可能会连续进位if(next == 1) str += '1';//旋转reverse(str.begin() , str.end());return str;}
4、题4 字符串最后一个单词的长度:
字符串最后一个单词的长度_牛客题霸_牛客网
既然是拿到最后一个单词,那么只要我们从后往后找到第一个空格就行了;
参考代码:
#include <iostream>
using namespace std;int main()
{//输入string s;getline(cin,s);//从后往前进行查找size_t pos = s.rfind(' ');cout<<s.size() - pos -1 <<endl;return 0;
}
需要注意的是,此处进行输入的时候不能使用cin 以及 scanf;
在控制台、终端输入的数据是输入在缓冲区之中;流提取cin、scanf 均是去缓冲区中拿数据;而cin、scanf 只要遇到空格或者换行符就会停止读取数据,即 cin、scanf 只会拿到空格、换行符之前的数据;
Q: 为什么cin 和 scanf 遇到空格或者换行符就停止读取?
- 因为在日常中我们会输入多个字符串、整型等;而当我们输入多个值的时候,就利用空格进行分割的;C/C++ 规定,用scanf 和 cin 的时候,不论读取的数据是什么类型,多个值之间默认用空格或者换行进行分割;
故而空格或者换行符会默认为是流提取cin 以及scanf 的分隔符,此时便会导致在读取带有空格的字符串,拿不到空格以后的字符;本题中需要利用string 的非成员函数 getline 来解决;
getline 即获取一行,遇见空格并不会结束读取,默认遇见换行符才会停止读取;除此之外,我们还可以指定getline 的终止符;
总结
熟悉使用 string 的接口函数~