【C++进阶】STL-string(2)
目录
1.string的接口
1.1 find & substr
1.1.1 找文件名后缀
find可以找字符串、字符、string类型,返回值是下标;
substr用来找子串,一般有两个形参,如果只填一个,那就会从当前位置开始找到最后;第二个形参是从当前位置开始往后找几个,例如:string str = "string.txt",先用find找到了.的位置,例如是pos,那么substr(str,1)就会找到'.' substr(str,2)就会找到'.t'
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
int main()
{
// find和substr接口
string str1 = "yulei.png";
string str2 = "yusanshi.avi";
string str3 = "yusanpang.jpg";
int pos1 = str1.find('.');
int pos2 = str2.find('.');
int pos3 = str3.find('.');
if (pos1 != string::npos) // npos表示没找到
{
cout << str1.substr(pos1) << endl;
cout << str2.substr(pos2) << endl;
cout << str3.substr(pos3) << endl;
}
}
如果一个文件使用tar压缩再打包,后缀就是.tar.zip,我只想要.zip可以怎么做呢?
使用rfind,从后往前找;

1.1.2 网址找域名
网址分为:协议 + 域名(或者ip) + 资源;
协议:
找:即可;
string url1 = "https://bilibili.com/profile/info";
size_t il = url1.find(":");
if (il != string::npos)
{
string protocal1 = url1.substr(0,il); // il是5,刚好是https的个数
cout << protocal1 << endl;
}
域名和资源怎么找:
找域名后面的/即可;
string url1 = "https://bilibili.com/profile/info";
size_t il = url1.find(":");
if (il != string::npos)
{
string protocal1 = url1.substr(0,il); // il是5,刚好是https的个数
cout << protocal1 << endl;
}
size_t posEnd = url1.find('/', il + 3); // com后的/
cout << url1.substr(il + 3, posEnd - (il + 3)) << endl;;// 从b开始到/
cout << url1.substr(posEnd + 1);

封装成一个函数:
// 封装url函数
void split_url(string url)
{
size_t pos1 = url.find(':');
string part1 = url.substr(0, pos1); // 协议
size_t pos2 = url.find('/', pos1 + 3); // 找域名后的/
string part2 = url.substr(pos1 + 3,pos2 - (pos1 + 3)); // 域名
string part3 = url.substr(pos2); // 资源
cout << "协议:" << part1 << endl;
cout << "域名:" << part2 << endl;
cout << "资源:" << part3 << endl;
}
int main()
{
string url1 = "https://bilibili.com/profile/info";
string url2 = "https://pan.baidu.com/pfile/video?path=";
string url3 = "https://leetcode.cn/problems/first-unique-character-in-a-string/description/";
split_url(url1);
split_url(url2);
split_url(url3);
}

1.1.3 几道oj题目
题目1:字符串最后一个单词的长度
描述
对于给定的若干个单词组成的句子,每个单词均由大小写字母混合构成,单词间使用单个空格分隔。输出最后一个单词的长度。
输入描述:
在一行上输入若干个字符串,每个字符串代表一个单词,组成给定的句子。
除此之外,保证每个单词非空,由大小写字母混合构成,且总字符长度不超过 103103 。
输出描述:
在一行上输出一个整数,代表最后一个单词的长度。
示例1
输入:
HelloNowcoder
13
在这个样例中,最后一个单词是 "HelloNowcoder""HelloNowcoder" ,长度为 1313 。
示例2
输入:
A B C D
1
思路:
注意这是一个oj题,有刚好和空格有关,所以,这里需要使用getline进行读取一行;
①读取完毕之后,只需要从后往前找到第一个空格;
②使用size接口获得字符串后面的位置;
③再使用这个位置 - 空格之后一个位置(最后一个单词的头);
即end - (pos + 1);即可;
④需要注意的是如果没有空格,说明字符串本身就是一个单词,直接输出它的size就可以了;

代码
#include <iostream>
#include<string>
using namespace std;
int main() {
string s;
// cin >> s; // cin遇到空格就会停止
getline(cin,s);
size_t pos;
if(s.rfind(' ') != string::npos)
{
pos = s.rfind(' ');
cout << s.size() - (pos + 1) << endl;
}else
{
// 不然就一个单词
cout << s.size() << endl;
}
}
题目2:验证回文串
描述
给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。
本题中,将空字符串定义为有效的 回文串 。
示例 1:
输入: s = "A man, a plan, a canal: Panama" 输出: true 解释:"amanaplanacanalpanama" 是回文串
示例 2:
输入: s = "race a car" 输出: false 解释:"raceacar" 不是回文串
提示:
1 <= s.length <= 2 * 105- 字符串
s由 ASCII 字符组成
思路
① 首先使用两个指针分别指向字符串的首尾,如果遇到非字符或者非数字的直接指针响中间靠拢;
②如果指针停下来,说明指针指向的一定是数字或者字符,此时比较如果不相等返回false;
③循环结束后,直接返回true;
代码
bool isCharOrNum(char ch)
{
if((ch >= 'a' && ch <= 'z')||(ch >= '0' && ch <= '9'))
{
return true;
}else
{
return false;
}
}
class Solution {
public:
bool isPalindrome(string s) {
// 所有大写转成小写
for(auto& ch : s)
{
if(ch >= 'A' && ch <= 'Z')
{
ch += 32; // 这里是引用,所以直接修改了
}
}
int begin = 0,end = s.size() - 1;
while(begin < end)
{
// 如果是字符或者数字就比对
while(begin < end && !isCharOrNum(s[begin]))
{
++begin;
}
while(begin < end && !isCharOrNum(s[end]))
{
--end;
}
if(s[begin] != s[end])
{
return false;
}
++begin;
--end;
}
return true;
}
};
题目3:字符串相加
描述:
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
示例 1:
输入:num1 = "11", num2 = "123" 输出:"134"
示例 2:
输入:num1 = "456", num2 = "77" 输出:"533"
示例 3:
输入:num1 = "0", num2 = "0" 输出:"0"
思路:
①使用两个指针,分别指向两个字符串的最后;
②如果有一个字符串指针end,>=0,那么就进入循环;
③分别取出当前指针指向的数字(如果存在);
④计算两位数的和;
⑤判断进位,若进位需要将和-10,进位为1;如果没有进位,进位是0;
⑥将结果拼到字符串末尾;
⑦出循环,判断是否还有进位,有进位就再拼一个1;
⑧将字符串逆置。
代码:
class Solution {
public:
string addStrings(string num1, string num2) {
int end1 = num1.size() -1;
int end2 = num2.size() -1; // 两个字符数字的指针
int next = 0; // 表示进位
string strRet;
int ret = 0;
while(end1 >= 0 || end2 >= 0) // 有一个数字没加完
{
int val1 = 0,val2 = 0;
// 取值
if(end1 >= 0)
{
val1 = num1[end1] - '0';
}
if(end2 >= 0)
{
val2 = num2[end2] - '0';
}
// 先相加,再判断进位,因为进位是上一个循环造成的
ret = val1 + val2 + next;
if(ret > 9)
{
ret -= 10;
next = 1;
}else
{
next = 0;
}
// 还原到字符串
strRet += (ret + '0');
--end1;
--end2;
}
// 如果两个数字同时end到-1,且还有进位,尾插一个1
if(next == 1)
{
strRet += '1';
}
// 由于是尾插,最后需要逆置
reverse(strRet.begin(),strRet.end());
return strRet;
}
};
题目4:字符串相乘
描述:
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = "2", num2 = "3" 输出: "6"
示例 2:
输入: num1 = "123", num2 = "456" 输出: "56088"
提示:
1 <= num1.length, num2.length <= 200num1和num2只能由数字组成。num1和num2都不包含任何前导零,除了数字0本身。
思路:
乘法:a*b,其实就是a个b相乘;
①写一个能循环a次的循环;
②每次循环+b即可;
代码:
string addStrings(string num1, string num2) {
int end1 = num1.size() -1;
int end2 = num2.size() -1; // 两个字符数字的指针
int next = 0; // 表示进位
string strRet;
int ret = 0;
while(end1 >= 0 || end2 >= 0) // 有一个数字没加完
{
int val1 = 0,val2 = 0;
// 取值
if(end1 >= 0)
{
val1 = num1[end1] - '0';
}
if(end2 >= 0)
{
val2 = num2[end2] - '0';
}
// 先相加,再判断进位,因为进位是上一个循环造成的
ret = val1 + val2 + next;
if(ret > 9)
{
ret -= 10;
next = 1;
}else
{
next = 0;
}
// 还原到字符串
strRet += (ret + '0');
--end1;
--end2;
}
// 如果两个数字同时end到-1,且还有进位,尾插一个1
if(next == 1)
{
strRet += '1';
}
// 由于是尾插,最后需要逆置
reverse(strRet.begin(),strRet.end());
return strRet;
}
class Solution {
public:
string multiply(string num1, string num2) {
// 乘法变加法
string zero("0");
string ret = "0";
while(zero != num1)
{
ret = addStrings(ret,num2);
zero = addStrings(zero,"1");
}
return ret;
}
};
这段代码的性能是有问题的,有没有聪明的友友,能够优化一下呢?答案将在下期揭晓。
更多推荐



所有评论(0)