🍅之前学习过类和对象,明确了C++是面向对象编程,那不得不提常见对象——字符串
目录
☃️1.基本介绍
☃️2.string中金典常见接口
🐝2.1 reserve()和resize()(capacity()和size())
🐝2.2 迭代器和反向迭代器(iterator(),begin(),end(),rbegin(),rend())
🐝2.3 c_str()
🐝2.4 substr()
🐝2.5 at()
🐝2.6 insert()和erase()
🐝2.7 find()和find_first_of()系列
🐝2.8 swap()
🐝2.9 reverse()
☃️3.用string接口写模拟oj
🐝3.1把字符串转换成整数
🐝3.2 字符串相加
🐝3.3 仅仅反转字母
🐝3.4 字符串中的第一个唯一出现一次的字符
🐝3.5 字符串最后一个单词的长度
🐝3.6验证回文串
🐝3.7反转字符串
🐝3.8反转字符串中的单词
🐝3.9字符串相乘
🐝3.10 找出字符串中第一个只出现一次的字符
☃️1.基本介绍
在C语言中我们也做过很多字符串的题目吗,但是真的有些题好麻烦,C++为了更方便操作提供了一系列在string库里的接口,string类是使用char(作为它的字符类型,使用它的默认char_traits和分配器类型
string类是basic_string模板类的一个实例,使用char来实例化basic_string模板类,并用char_traits
和allocator作为basic_string的默认参数
注意:这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作
使用接口函数一定要包含头文件
☃️2.string中金典常见接口
🐝2.1 reverse()和resize()(capacity()和size())
最最金典的就是这个老生常谈的问题
首先字面意思,capacity指string类的容量,不同编译器初始化时设置的capacity不同,返回值是size_t,调用方式如下
string s("hello world");
size_t a=s.capacity();
size()是字符串长度,不包括'\0',size()接口和length()接口功能 用法完全一样,返回值是size_t
string s("hello world");
size_t a=s.size();
reserve()和resize()就是围绕上面两个参数(容量,长度)展开
一言蔽之:
reserve() 只修改容量,当调整的容量小于当前空间容量时,容量不减少
resize() 只修改长度
看下实例
很奇怪,为什么两个reserve(100)之后的修改值不一样
这个就是设计者的设计,可能是函数里面的数字n,也可能是更大,但是我们做题都是默认n,不会考虑特殊情况(在没有说明的情况下),
此外,第一次reserve(100) 下面reserve(50)不会再修改容量值
resize(n)的结果和想象的一样,不做解释
🐝2.2 迭代器和反向迭代器(iterator(),begin(),end(),rbegin(),rend())
首先看一下begin() 和 end() 两个接口,字面意思就是指向头尾的指针,注意类型是迭代器 类似于指针
关于迭代器这里不做详细描述,以后会写一篇博客,具体谈一谈迭代器的多种玩法
先来看一个很简单的正向迭代器,他往往就是和begin() end() 配合使用的,在oj中begin()和end()也是常用的
有正向就有反向 ,rbegin() 和 rend() 就是从字符串结尾开始匹配
反向迭代器指针,当然要搭配反向迭代器
当然还有const类型的迭代器
普通版本的可读可写
特殊版本
string::const _iterator begin() const;
在begin()接口,就能看到是有一个const迭代器的
可以验证 确实是不可以修改的
当然还有const的反向迭代器,举一反三
🐝2.3 c_str()
这个接口的返回值是const char *类型 指针,存储字符串位置的地址
这个函数是十分不可靠的,因为使用c_str()进行字符串赋值之后,如果对string中的char* 改变,那么c_str()中的值就很不可靠
储存字符串位置的指针 解引用找到的就是整个字符串
但是想打印地址的时候需要强转一下
🐝2.4 substr()
子串,从pos位置取len长度的子串
若len不指定/为负/为空/大于size() 都是取到字符串结束
默认从左开始数pos位置
🐝2.5 at()
访问pos位置的元素
字符串当然可以用[ ]访问,越界时直接报错 断言
但是使用at(),越界时抛异常,而异常可以被捕获(以后细讲),格式如下
实际中很少使用at(),因为和下标[ ]访问没什么区别
🐝2.6 insert()和erase()
种类真的是.......
总结一下就是死一个参数一般是要插入的位置,第二个参数是数字代表要插入的个数,是字符代表要插入的字符,是字符串同理,第三个参数是字符或者字符串
位置pos 代表你想在pos之前插入
注意插入空格的时候一定要插入字符的形式,不可以插入空串
erase
第一个参数是数字代表要删除的位置,第二个参数是数字代表要删除的长度
参数也可以是迭代器,就是删除迭代器位置的字符
🐝2.7 find()和find_first_of()系列
第一个参数一般是要寻找的字符或者字符串,第二个参数是开始寻找的位置,默认缺省值是0位置
返回值:出现的位置/ string::npos
npos是size_t的最大值,一般寻找失败都是返回npos
当然还有rfind,就是倒着找字符
其实这个很好用,可以看一道笔试题
替换空格
解法一:
既然是替换,string也提供了替换的相应函数
可以看到效率十分低
class Solution {
public:
string replaceSpace(string s) {
size_t pos=s.find(' ');
while(pos!=string::npos)
{
s.replace(pos,1,"%20");
pos=s.find(' ');
}
return s;
}
};
解法二:
把replace的原理自己写一下(自己扩容,然后创建新串,以空间换时间)
class Solution {
public:
string replaceSpace(string s) {
size_t num=0; //提前计算好空格的数量方便扩大capacity
for(auto ch:s)
{
if(ch==' ')num++;
}
s.reserve(num*2+s.size());
string newstr;
for(auto ch:s)
{
if(ch != ' ')
newstr+=ch;
else
newstr+="%20";
}
return newstr;
}
};
find_first_of(const string&str,size_t pos=0)
从字符串中找 在str中出现的字符,出现了就停一下
返回值:出现的位置/string::npos
把每一个出现a的位置都替换成*
还有他的好多兄弟
基本上望文生义,大家可以去网站上自己搜索cplusplus.com
🐝2.8 swap()
之前我们说std库函数已经有swap()
但是这个string类的函数,可以直接交换两个字符串的指针,对于字符串来说效率更高
🐝2.9 reverse()
revers()函数并不是string类的接口函数 ,但是他很常用
参数一般是迭代区间
string.reverse(迭代器起始,迭代器末尾);
☃️3.用string接口写模拟oj
🐝3.1把字符串转换成整数
首先要处理前面的加减号,并且让遍历数字的时候可以从下标1开始
第一个数字的权重要10倍增长
class Solution {
public:
int StrToInt(string str) {
int flag=1;
int i=0;
if(str[i]=='-' || str[0]=='+')
{
if(str[0]=='-')
flag=-1;
i++;
}
int ans=0;
for(;i<str.size();i++)
{
if(str[i]<'0'||str[i]>'9')
return 0;
ans=ans*10+str[i]-'0';
}
return flag*ans;
}
};
🐝3.2 字符串相加
注意要进位,并且最后如果进位数字不是0,还需要把最后一位加上
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1,end2=num2.size()-1;
string ans("");
int tmp=0;//进位
while(end1>=0 &&end2>=0)
{
int a=num1[end1]-'0',b=num2[end2]-'0';
if(a+b+tmp<10)
{
ans+=a+b+tmp+'0';
tmp=0;
}
else
{
ans+=(a+b+tmp)%10+'0';
tmp=(a+b+tmp)/10;
}
end1--;end2--;
}
while(end1>=0)
{
if(num1[end1]-'0'+tmp<10)
{
ans+=num1[end1]+tmp;
tmp=0;
}
else
{
ans+=(num1[end1]-'0'+tmp)%10+'0';
tmp=(num1[end1]-'0'+tmp)/10;
}
end1--;
}
while(end2>=0)
{
if(num2[end2]-'0'+tmp<10)
{
ans+=num2[end2]+tmp;
tmp=0;
}
else
{
ans+=(num2[end2]-'0'+tmp)%10+'0';
tmp=(num2[end2]-'0'+tmp)/10;
}
end2--;
}
if(tmp)
{
ans+=tmp+'0';
}
int begin=0,end=ans.size()-1;
while(begin<end)
{
swap(ans[begin++],ans[end--]);
}
return ans;
}
};
🐝3.3 仅仅反转字母
先判断一下是不是字符(有库函数)
class Solution {
public:
string reverseOnlyLetters(string s) {
size_t begin =0,end=s.size()-1;
while(begin<end)
{
while(begin<end && !isalpha(s[begin]))
begin++;
while(begin<end && !isalpha(s[end]))
end--;
swap(s[begin++],s[end--]);
}
return s;
}
};
🐝3.4 字符串中的第一个唯一出现一次的字符
还是传统的映射
class Solution {
public:
int firstUniqChar(string s) {
int a[26]={0};
for(auto ch:s)
{
a[ch-'a']++;
}
for(int i=0;i<s.size();i++)
{
if(a[s[i]-'a']==1) return i;
}
return -1;
}
};
🐝3.5 字符串最后一个单词的长度
从后往前找空格,然后处理空格到结尾这段子串
#include <iostream>
#include <string>
using namespace std;
int main() {
string str;
getline(cin,str);
size_t a=str.rfind(' ');
if(a!=string::npos)
{
cout<<str.size()-a-1<<endl;
}
else {
cout<<str.size()<<endl;
}
return 0;
}
🐝3.6验证回文串
去掉非字母数字的字符,然后把干净的字符串逆置看是否相等
class Solution {
public:
bool isPalindrome(string s) {
string a;
for(auto ch:s )
{
if(isalnum(ch))
a+=tolower(ch);
}
string rev(a.rbegin(),a.rend());
return rev==a;
}
};
🐝3.7反转字符串二
class Solution {
public:
string reverseStr(string s, int k) {
int n=s.size();
for(int i=0;i<n;i+=2*k)
{
reverse(s.begin()+i,s.begin()+min(n,i+k));
//更小的是n(全翻转),代表i+k>n,n-i<k(剩余量<k)
//更小的是i+k(翻转前k),代表i+k<n,n-i>k,剩余量>k
}
return s;
}
};
🐝3.8反转字符串中的单词 III
以空格为分割,把握好结束条件
class Solution {
public:
string reverseWords(string s) {
int begin = 0;
int space = s.find(' ');
while (begin < s.size())
{
int i = begin;
int ret = space - 1;
for (; i < ret; i++)
{
swap(s[i], s[ret--]);
}
begin = space + 1;
space = s.find(' ', space + 1);
if (space == string::npos && begin < s.size())
{
space = s.size();
}
else if (space == string::npos && begin >= s.size())
return s;
}
return s;
}
};
🐝3.9字符串相乘
和相加差不多思路
class Solution {
public:
string multiply(string num1, string num2) {
if(num1=="0" || num2=="0")
return "0";
int end1=num1.size(),end2=num2.size();
auto a=vector< int>(end1+end2+1);
for(int i=end1-1;i>=0;i--)
{
int tmp1=num1.at(i)-'0';
for(int j=end2-1;j>=0;j--)
{
int tmp2=num2.at(j)-'0';
a[i+j+1]+=tmp1*tmp2;
}
}
for(int i=end2+end1-1;i>0;i--)
{
a[i-1]+=a[i]/10;
a[i]%=10;
}
int index=a[0]==0?1:0;
string ans;
while (index < end1+end2) {
ans.push_back(a[index]);
index++;
}
for (auto &c: ans) {
c += '0';
}
return ans;
}
};
🐝3.10找出字符串中第一个只出现一次的字符
一定要注意,是原串里第一个出现的,而不是传统的映射关系
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
int main(){
string s;
int flag = -1;
while(getline(cin, s)){
for(int i = 0; i < s.size(); i++){
if(s.find(s[i]) == s.rfind(s[i])){
flag = 1;
cout<<s[i]<<endl;
break;
}
}
if(flag == -1){
cout<<-1<<endl;
}
}
}
创作不易,感谢观看