算法学习笔记(C++)——字符串string处理
string基础知识
- 为使用string标准模板,需要添加头文件# include
- 关于其初始化,可直接使用字符串给变量赋值
string str = "hello world";
// or
string str = str + " !!!";
- 关于其长度,可以使用size()和length()两种方法
- 关于其访问,有两种方式:下标访问和迭代器访问
(1)下标访问:
string str = "hello world";
for (int i=0; i<str.size(); ++i){
printf("%c", str[i]);
}
(2)迭代器访问
string str = "hello world";
for (string::iterator it = str.begin(); it !=str.end(); ++it){
printf("%c", *it);
}
- 关于对string中的元素进行操作,包括
(1)在指定位置插入insert()
str.insert(index, str);
第一个参数为插入的位置index
第二个参数为插入的字符串
(2)在指定位置删除 erase()
str.erase(first_char, length_of_erase);
第一个参数为删除的开始位置index
第二个参数为删除字串的长度,default为删除至string末端
(3)清空字符串clear()
无参数
-
关于字符串参与的运算
字符串加法表示连字符串相连
字符串的"==", “<=”, ">"这类运算,是基于字典序进行大小比较的 -
关于其他的一些常用函数
(1)find()
在字符串中寻找特定的字符或字符串,找到则返回相应的下标,否则返回string::npos(int类型接收的情况下,为-1)
string渗透入= "hello world";
int found = str.find("world");
if(found != string::npos){
cout << found << endl;
}
found = str.find('.');
(2)substr()
str.substr(begin_index, length)
第一个参数为开始位置
第二个参数为字符串总长度
string str1 = "we think in generalities";
string str2 = str1.substr(3, 5);
字符串应用实例
注:字符串应用过程中,常涉及边界问题
且,读入string过程中,若字符串中间包含空格,则不能再用cout和scanf进行读取,会在空格处终止字符串的load,可以用getline避免读取中断
题目:
密码加密问题:
对于明文中的A~Z的每个字符,用字母表中后5位所对应的字符代替,就能够得到密文,如A->F,对于明文中的V~Z(最后五个字符)则在密文中对应A~Z。
现需要将密文转换为明文
输入格式:
每一行密文的前一行为START,后一行为END,最终读取到ENDOFINPUT时结束程序。
输出格式为若干行,每行一段明文。
# include <string>
# include <cstdio>
# include <iostream>
using namespace std;
int main(){
string str;
// the first line, deciding a new case of the end of code
while(getline(cin, str)){
if (str == "ENDOFINPUT"){
break;
}
// text which is encoded
getline(cin, str);
for (int i=0; i<str.size(); ++i){
if ( 'A' <= str[i] && str[i] <= 'Z'){
str[i] = (str[i] - 5 + 26 - 'A') % 26 + 'A';
}
}
string str1;
// eat the string "END"
getline(cin, str1);
cout << str << endl;
}
return 0;
}
统计一个给定字符串中指定的字符出现的次数
输入格式:
每个测试样例包括两行,第一行为长度不超过5的字符串,第二行为长度不超过80的字符串(包含空格,即空格也是可能被要求统计的字符)当读取到‘#’时,输入结束
输出格式:
对每个测试样例,统计第一行中字符串的每个字符在第二行的字符串中出现的次数,并按照如下格式输出。
c0 n0
c1 n1
c2 n2
# include <cstdio>
# include <iostream>
# include <string>
# include <cstring>
using namespace std;
int number[128];
int main(){
// record appearing times for every char
string str1;
string str2;
while (getline(cin, str1)){
if (str1=="#"){
break;
}
// initial the array
memset(number, 0, sizeof(number));// sizeof() returns how many bytes the array has
getline(cin, str2);
// count appearing times
for (int i=0; i<str2.size(); ++i){
number[str2[i]] += 1;
}
for (int i=0; i<str1.size(); ++i){
printf("%c %d \n", str1[i], number[str1[i]]);
// cout << str1[i] << " " << str2[str1[i]] << endl;
}
}
return 0;
}
字符串匹配问题——KMP算法
对于text字符串和pattern字符串的匹配问题,有一种高效的KMP算法:
其核心为,在模式串发生失配时,并不是从下一个字符串开始,从头开始重新匹配,而是利用已有的信息,跳过一些不可能成功匹配的位置,以便尽量减少模式串和珠串的匹配次数,快速完成匹配任务。
关于KMP算法的时间复杂度:
只需要遍历一遍模式串即可获得next表,使用next表遍历以便文本串即可获得字符串的匹配情况,故KMP算法的时间复杂度为O(m+n)
样例:
计算text文本串中pattern成功匹配的次数
# include <cstdio>
# include <string>
# include <iostream>
using namespace std;
const int MAXN = 100;
int nextTable[MAXN];
void GetNextTable(string pattern){
int m = pattern.size();
// initial
memset(nextTable, 0, sizeof(nextTable));
int j = 0;
nextTable[j] = -1;
int i = nextTable[j];
while (j<m){
if(i==-1 || pattern[i]==pattern[j]){
++i;
++j;
nextTable[j] = i;
}
else{
i = nextTable[i];
}
}
return ;
}
int KMP(string pattern, string text){
// the number of pattern appears
int number = 0;
int m = pattern.size();
int n = text.size();
int j = 0; // match with pattern
int i = 0; // match with text
while (i < n){
if (j==-1 || text[i]==pattern[j]){ // no error just now
++i;
++j;
}
else{ // error in match
j = nextTable[j];
}
if (j == m){ // successfully matched
++number;
j = nextTable[j];
}
}
return number;
}
int main(){
int casenumber;
cin >> casenumber;
while (casenumber--){
string pattern;
string text;
cin >> pattern >> text;
// get the next table
GetNextTable(pattern);
// KMP algorithm
cout << KMP(pattern, text);
}
return 0;
}