题目1:344.反转字符串
解法:双指针法
字符串也可以理解成一种数组,然后定义前后两个指针,同时向中间移动并交换元素
class Solution {
public:
void reverseString(vector<char>& s) {
for (int left = 0, right = s.size() - 1; left < right; left++, right--) { //条件也可以改成left<.size()/2 遍历到字符串的一半就可以返回结果
swap(s[left], s[right]);
}
}
};
题目2:541.反转字符串Ⅱ
解法:模拟
反转每个下标从 2k2k 的倍数开始的,长度为 kk 的子串。若该子串长度不足 kk,则反转整个子串。
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) { //使用+=让i每次移动2k,然后判断是否反转
if (i + k <= s.size()) { //1.每隔2k个字符的前k个字符进行反转 2.剩余字符小于2k但大于或等于k个,则反转前k个字符
reverse(s.begin() + i, s.begin() + i + k); //reverse()会将区间[beg,end)内的元素全部逆序
continue; //直接进入下一轮循环
}
reverse(s.begin() + i, s.begin() + s.size()); //3.剩余字符少于 k 个,则将剩余字符全部反转
}
return s;
}
};
官方给出的代码更加简洁:
class Solution {
public:
string reverseStr(string s, int k) {
int n = s.length();
for (int i = 0; i < n; i += 2 * k) {
reverse(s.begin() + i, s.begin() + min(i + k, n));
}
return s;
}
};
题目3:剑指Offer05.替换空格
解法:双指针法
解题思路:
将空格变成%20(一个字符变成三个字符),因此可以将字符串的大小resize,然后遍历字符串将空格替换成%20
如果从前向后填充,时间复杂度就变成了O(n2),因为每次添加元素都要将添加元素之后的所有元素向后移动。
class Solution {
public:
string replaceSpace(string s) {
int count = 0; //空格数
int oldsize = s.size(); //替换前的字符串长度
for (int i = 0; i < oldsize; i++) { //统计字符串中的空格数
if (s[i] == ' ') {
count++;
}
}
s.resize(s.size() + 2*count); //扩充字符串
int newsize = s.size(); //扩充后字符串长度
//从后向前将空格替换为%20
for (int i = newsize-1, j = oldsize-1; j < i; i--, j--) { //i指向新长度的末尾,j指向旧长度的末尾
if (s[j] != ' ') {
s[i] = s[j];
}
else {
s[i] = '0';
s[i - 1] = '2';
s[i - 2] = '%';
i -= 2;
}
}
return s;
}
};
评论区大佬用了字符数组的解法,非常的巧妙:
与双指针法相比,双指针法是在原来的字符串中进行改动,字符数组是重新创建了一个新的数组
class Solution {
public:
string replaceSpace(string s) { //字符数组
string array; //存储结果
for(auto &c : s){ //遍历原字符串
if(c == ' '){
array.push_back('%');
array.push_back('2');
array.push_back('0');
}
else{
array.push_back(c);
}
}
return array;
}
};
题目4:151.颠倒字符串中的单词
解法一
倒序遍历,超级简单的代码
class Solution {
public:
string reverseWords(string s) {
string result; //存放结果的字符串
int i = s.size();
while (i) { //倒叙遍历字符串
int count = 0; //计数有多少个非空格的字符
while (i > 0 && s[i] == ' ') i--; //遍历空格
while (i > 0 && s[i] != ' ') i--, count++; //遍历字符
if (count > 0) result += s.substr(i + 1, count) + ' '; //截取的是从i+1开始(此时的i已经不指向字符),截取count个字符
}
return result.substr(0, result.size() - 1); //最后的result中多了个空格,要注意去掉
}
};
解法二:双端队列+双指针
官方提供了一种双端队列的方法,即[deque容器,支持从队列头部插入的方法
C++ STL deque容器(详解版)
沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可。
class Solution {
public:
string reverseWords(string s) {
int left = 0, right = s.size() - 1;
// 去掉字符串开头的空白字符
while (left <= right && s[left] == ' ') ++left;
// 去掉字符串末尾的空白字符
while (left <= right && s[right] == ' ') --right;
deque<string> d;
string word;
while (left <= right) {
char c = s[left];
if (word.size() && c == ' ') {
// 将单词 push 到队列的头部
d.push_front(move(word));
word = "";
}
else if (c != ' ') {
word += c;
}
++left;
}
d.push_front(move(word));
string ans;
while (!d.empty()) {
ans += d.front();
d.pop_front();
if (!d.empty()) ans += ' ';
}
return ans;
}
};
题目5:剑指Offer58.II.左旋转字符串
解法一:字符串切分与拼接
解题思路:
获取str[n:] 和 str[:n]子串,目标串target = str[:n] + str[n:];
class Solution {
public:
string reverseLeftWords(string s, int n) {
string str1 = s.substr(0, n); //str[:n]
string str2 = s.substr(n, s.size() - n); //str[n:]
string newstr = str2 + str1;
return newstr;
}
};
解法二:翻转
解题思路:
通过局部翻转+整体翻转达到左旋转的目的,不需要定义新的字符串,完全在原字符串上操作
首先翻转str[:n]子串,其次翻转str[n:]子串,最后翻转str.
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin() + n); //翻转区间前n的子串
reverse(s.begin() + n, s.end()); //翻转区间n到末尾的子串
reverse(s.begin(), s.end()); //翻转整个字符串
return s;
}
};