1.C++字符串
c++提供了一下两种类型的字符串表示形式:
- c风格字符串
- c++引入的string类类型
1.1C风格字符串
C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 RUNOOB 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 RUNOOB 的字符数多一个。
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};
依据数组初始化规则,您可以把上面的语句写成以下语句
char site[] = "RUNOOB";
其实,您不需要把 null 字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 \0 放在字符串的末尾。让我们尝试输出上面的字符串
相关函数
1.2 C++中的string类
C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。我们将学习 C++ 标准库中的这个类,现在让我们先来看看下面这个实例:
现在您可能还无法透彻地理解这个实例,因为到目前为止我们还没有讨论类和对象。所以现在您可以只是粗略地看下这个实例,等理解了面向对象的概念之后再回头来理解这个实例
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "runoob";
string str2 = "google";
string str3;
int len ;
// 复制 str1 到 str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接 str1 和 str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,str3 的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
str3 : runoob
str1 + str2 : runoobgoogle
str3.size() : 12
相关函数
函数 | 功能 | 用法例子 |
---|---|---|
length | 返回字符串的长度 | size_t len = str.length(); |
size | 返回字符串的长度(与length相同) | size_t len = str.size(); |
empty | 检查字符串是否为空 | bool isEmpty = str.empty(); |
clear | 清空字符串 | str.clear(); |
append | 在字符串末尾添加另一字符串或字符 | str.append("world"); 或 str.append(1, '!'); |
push_back | 在字符串末尾添加一个字符 | str.push_back('!'); |
insert | 在指定位置插入字符或字符串 | str.insert(5, "abc"); |
erase | 移除字符串中的字符或子字符串 | str.erase(5, 3); |
replace | 用新字符串替换指定范围内的子字符串 | str.replace(5, 3, "xyz"); |
substr | 提取子字符串 | std::string sub = str.substr(5, 3); |
find | 查找子字符串首次出现的位置 | size_t pos = str.find("abc"); |
rfind | 查找子字符串最后一次出现的位置 | size_t pos = str.rfind("abc"); |
find_first_of | 查找字符串中任意一个字符首次出现的位置 | size_t pos = str.find_first_of("aeiou"); |
find_last_of | 查找字符串中任意一个字符最后一次出现的位置 | size_t pos = str.find_last_of("aeiou"); |
find_first_not_of | 查找字符串中第一个不属于指定字符集合的位置 | size_t pos = str.find_first_not_of("aeiou"); |
find_last_not_of | 查找字符串中最后一个不属于指定字符集合的位置 | size_t pos = str.find_last_not_of("aeiou"); |
compare | 比较两个字符串 | int result = str.compare("hello"); |
c_str | 返回C风格字符串(以null结尾的字符数组) | const char* cstr = str.c_str(); |
copy | 将字符串的内容复制到字符数组中 | str.copy(buffer, len); |
resize | 调整字符串大小 | str.resize(20, '!'); |
std::stoi | 将字符串转换为整数 | int num = std::stoi("123"); |
std::stod | 将字符串转换为双精度浮点数 | double num = std::stod("123.45"); |
std::to_string | 将数值转换为字符串 | std::string str = std::to_string(123); |
std::getline | 从输入流读取一行到字符串 | std::getline(std::cin, str); |
2.字符串相关算法题
2.1反转字符串
#include <iostream>
#include <vector>
#include <string>
#include <utility>
using namespace std;
class Solution {
public:
void reverseString(vector<char>& s)
{
int i = 0, j = s.size() - 1;
while(i < j)
{
swap(s[i], s[j]);
i++;
j--;
}
}
};
2.2反转字符串II
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
string reverseStr(string s, int k)
{
for (int i = 0; i < s.size(); i += 2 * k)
{
if (i + k <= s.size())
{
reverse(s.begin() + i, s.begin() + i + k);
}
else
{
reverse(s.begin() + i, s.end());
}
}
return s;
}
};
2.3反转字符串里的单词(*)
双指针版
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
string reverseWords(string s) {
int s_len = s.length();
// 移除多余空格符
int fast = 0;
int low = 0;
// 移除字符串之前的空格
while (fast < s_len && s[fast] == ' ')
{
fast++;
}
// 移除单词间空格
while (fast < s_len)
{
if (s[fast] == ' ' && (fast + 1 < s_len && s[fast + 1] == ' '))
{
fast++;
}
else
{
s[low++] = s[fast++];
}
}
// 移除字符串后的空格
if (low > 0 && s[low - 1] == ' ')
{
low--;
}
s.resize(low);
// 翻转整个字符串
reverse(s.begin(), s.end());
// 翻转每个单词
int i = 0;
while (i < low)
{
int j = i;
while (j < low && s[j] != ' ')
{
j++;
}
reverse(s.begin() + i, s.begin() + j);
i = j + 1;
}
return s;
}
};
迭代器版
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
string reverseWords(string s)
{
// 删除前面的空格
auto it1 = s.begin();
while(it1 != s.end() && *it1 == ' ')
{
it1 = s.erase(it1);
}
// 删除后面的空格
auto it2 = s.end();
while(it2 != s.begin() && *(it2 - 1) == ' ')
{
it2 = s.erase(it2 - 1);
}
//反转整个字符串
reverse(s.begin(), s.end());
//反转每个单词
auto start = s.begin();
for(auto it = s.begin(); it <= s.end(); it++)
{
if (it == s.end() || *it == ' ')
{
reverse(start, it);
start = it + 1;
}
}
// 删除多余空格
for(auto it = s.begin(); it != s.end();)
{
if(*it == ' ')
{
auto next_it = it + 1;
while(next_it != s.end() && *next_it == ' ')
{
next_it = s.erase(next_it);
}
it = next_it;
}
else
{
++it;
}
}
return s;
}
};
int main(void)
{
Solution sol;
string s = " a good example ";
s = sol.reverseWords(s);
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
return 0;
}
注意:
- 分别实现移除字符串前面空格,字符串后面空格,字符串多余空格和反转字符串的单词(先整个字符串反转,再每个单词反转)
- 类别移除零,主要用双指针法实现
2.4找出字符串中第一个匹配项的下标
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution
{
public:
int find_index(string s, string t)
{
if (t.size() > s.size()) return -1; // 如果 t 比 s 长,直接返回 -1
int res = -1;
for(int i = 0; i <= s.size() - t.size(); i++)
{
if(s[i] == t[0])
{
string subs = s.substr(i, t.size());
if (subs == t)
{
res = i;
break;
}
}
}
return res;
}
};
2.5重复的子字符串(*)
题目
如果一个非空字符串s可以由它的一个子串重复多次构成,可以理解为s中存在m个子串,那么当两个字符串结合起来变成ss时,字符串s在新字符串ss的第二次位置不等于s的长度(相当于前一个字符串s中有n个子串,在后一个字符串中有m-n个子串,所以此时的位置不等于s的长度);反之,一个非空字符串s不可以由它的一个子串重复多次构成,那么当两个字符串结合起来变成ss时,字符串s在新字符串ss的第二次位置就在后一个字符串首字符的位置,其位置刚好等于s的长度。根据这一特征来判断
- find函数
string str1, str2;
str1.find(str2); //从串str1中查找时str2,返回str2中首个字符在str1中的地址
str1.find(str2,5); //从str1的第5个字符开始查找str2
代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
return (s+s).find(s,1)!=s.size();
}
};