这篇文章将会总结一些处理字符串、进制转换等等的常见的、非常有用的技巧和函数。后续会随时更新本文章,希望大家收藏、留言,一起学习进步!
对于特别简单的函数,就不写函数的详细原型啦!
具体包含四部分,可以根据目录去寻找:
1.char*函数 2.string函数 3.数符转换和进制转换 4.字符串函数优化(kmp替换string find,字符串哈希部分替换string substr)
5.位运算技巧
6.按空格分割字符串
目录
char*函数
strlen函数:
strcmp函数:
strcat函数:
strcpy函数:
memset函数:
cin.getline函数:
读取char*时的下标问题
char*转string
string函数
size/length函数
push_back()与insert()函数
compare函数/append函数
erase函数
replace函数
string转char*
find函数
substr函数
数符转换和进制转换
sprintf函数
itoa/atoi
进制转换补充
字符串函数优化
位运算技巧
字符串按空格分割
char*函数
strlen函数:
求一个char数组的长度,<cstring>
char str[10]
scanf("%s",str);
int len=strlen(str);
cout<<len<<endl;
strcmp函数:
比较两个char数组的字典序,<cstring>
char a[6]="a"
char b[6]="ab"
char c[6]="ac"
cout<<strcmp(a,b)<<endl;//-1
cout<<strcmp(c,b)<<endl;//1
cout<<strcmp(a,a)<<endl;//0
strcat函数:
连接两个char数组,<cstring>
char a[6]="ab"
char b[6]="bc"
strcat(a,b)
cout<<a<<endl;//abbc
cout<<b<<endl;//bc
strcpy函数:
把一个char数组复制到另一个上面,<cstring>
char a[6]="ab"
char b[6]="bc"
strcpy(a,b)
cout<<a<<endl;//bc
cout<<b<<endl;//bc
memset函数:
初始化数组,<cstring> int数组也可以用
char a[100];
memset(a,'0',sizeof a);
cin.getline函数:
读取一行字符,包括空格,遇到换行符终止,丢弃换行符,<istream>
第一个参数:数组名,第二个参数:最多输入的字符数(注意字符串后面有一个空字符,所以一般这个参数比实际最大长度多1,比如读取abcd就写5)
int a[100];
cin.getline(a,100);//最多输入99个字符,即(0,99);
cout<<a;
还有cin.get函数可以读取一行,但是对于读取一行的函数就掌握getline就够用了!比如下面这段代码换成get就会出问题
while(n--)
{
char a[100];
cin.getline(a,100)//最多输入99个字符,即(0,99);
cout<<a<<endl;
}
读取char*时的下标问题
如果想让读取到的char*下标从1开始,cin,scanf,getline都支持下面这种写法,string就不支持
char a[10];
// cin>>a+1;
// scanf("%s",a+1);
cin.getline(a+1,10);
cout<<a[1];
return 0;
char*转string
方法非常简单,直接让一个char*赋值给string即可
char a[100]="anc";
string b=a;
cout<<b<<endl;//anc
string函数
包含STL神器之一:string 的各种常用函数,头文件皆为<string>
size/length函数
返回string长度
string a="123";
cout<<a.size()<<endl;//3
cout<<a.length()<<endl;//3
push_back()与insert()函数
前者:向字符串尾端插入一个字符
后者:下面展示常用的,当然还有别的方法,只不过可以由最基本的转换而来
string a="123";
string b="56";
char c='7';
a.push_back('4');
cout<<a<<endl;//1234
a.insert(a.begin(),b);//不合法
a.insert(0,b);//合法,a="123456"
a.insert(a.begin(),c);//合法,a="1234567"
compare函数/append函数
建议直接用< > == 和 +=符号替代
erase函数
常用来删除一个区间内的字符,区间左闭右开
string str="123456";
str.erase(1,4);
cout<<str<<end;//156
replace函数
常用来把str的某一个区间替换成重复的单个字符或者整个其它字符串
下面展示几种常用的写法
string a="123456";
string b="789";
char c='0'
a.replace(0,5,b);//a="7896" 把a的[0,5)变成b
a.replace(0,2,3,c);//a="00096" 把a从下标0开始往后的2个字符替换成3个字符c
string转char*
直接用c_str()即可
char a[100];
string b="123";
a=b.c_str();
//也可以这样:scanf("%s",b.c_str());
find函数
模式匹配函数,直接放例子,通俗易懂
string a="123123";
cout<<a.find('1')<<endl;//0
cout<<a.find('1',2)<<endl;//3 因为是从下标2往后找
substr函数
str.substr(pos,length)从pos开始往后截取长度为length的子串并返回
string a="1234";
string b=a.substr(2,2);//b="34"
数符转换和进制转换
本部分将会介绍整型和字符串常用的转换方法,由于这个转换常常可以伴随进制转换,所以放在一起总结,这也是字符串模拟题目中常常考察的技能!!!
sprintf函数
把一个格式化字符串,写入字符数组,返回写入数组的总字符数,如果失败,返回负数
举例:
char a[100];
int b=5;
sprintf(a,"1234%d",b);//a="12345"
itoa/atoi
itoa用于将十进制整数变为任意进制的字符数组形式
atoi用于将字符数组变为十进制整数(不支持类型转换)
详见:atoi itoa简介
进制转换补充
看到这里,可能会问:那如何把a进制整数转为b进制整数呢?答案是c++没有这个库函数,所以需要自己写一个函数,先把a进制转10进制,再把10进制转b进制
同理,c++也没有把一个a进制字符串变为十进制整数的函数,需要麻烦自己写了
字符串函数优化
find函数虽然好用,但是时间上不如kmp算法,所以当写一个题目用findTLE的使用,换成kmp吧,下面是acwing算法基础课的kmp板子:
#include <iostream>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
int ne[N];
char s[M], p[N];
int main()
{
cin >> n >> p + 1 >> m >> s + 1;
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == n)
{
printf("%d ", i - n);
j = ne[j];
}
}
return 0;
}
再来说substr,比如下面这种题(来自acwing算法基础课),第一反应可能是用substr,但可能会TLE
所以在此放一下acwing算法基础课字符串哈希的板子,大家触类旁通,在某种情况下可以参考
#include<iostream>
using namespace std;
const int N=100010,P=131;
typedef unsigned long long ULL;
char str[N];
ULL p[N],h[N];
ULL get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
int n,m;
cin>>n>>m;
getchar();
for(int i=1;i<=n;i++)scanf("%c",&str[i]);
p[0]=1;
for(int i=1;i<=n;i++)
{
h[i]=h[i-1]*P+str[i];
p[i]=p[i-1]*P;
}
while(m--)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
位运算技巧
对于二进制字符串模拟这种题,比如csp第30次认证第3题,很多时候用到位运算的技巧。下面是链接
csp30次认证第3题
x&-x:可以求x最低位的一个1出现在哪一位
比如100011算完就是000001
10010算完就是00010
a>>b&1:检查a的第b位(最低位是0)是否为1
a&1==1:奇数
a&1==0:偶数
二进制“拼接”:
比如两个二进制数100和010想变成100010,只需让100左移3然后加上010即可
二进制“截取”:
比如10101想求中间的三位数“010”,首先令a=10101 a>>=1 b=1<<3 c=a-b c即为答案
~i:判断i是否为0
由此可以发现如果可以灵活使用位运算,很多时候处理二进制数的时候可以迎刃而解
字符串按空格分割
像第三次ccfcsp的第三题:csp3次认证第3题就会常常用到这种分割技巧,方法在之前的文章中已经讲过,给出连接如下:
stringstream字符串分割、字符串拼接