344.反转字符串
要点
swap不需要include文件,reverse要引入algorithm文件
双指针
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i=0, j=s.size()-1; i<j; i++, j--) {
swap(s[i], s[j]);
}
}
};
总结
头尾两个指针相向移动,互换对应位置的元素
541.反转字符串II
要点
i, i+2k都是某个2k组的第一个元素,所以s.begin()+i+k不用再+1
模拟
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.length(); i += (2*k)) {
// 当前这个2k组的前k个都在
if (i+k < s.length()) reverse(s.begin()+i, s.begin()+i+k); //--
else {
// 否则只翻转剩下的元素
reverse(s.begin()+i, s.end());
}
}
return s;
}
};
总结
这是一道模拟题,根据题目的意思设置跨度为2k的指针i,指向某2k组的第一个元素。再根据两条规则翻转字符串
剑指 Offer 05. 替换空格
要点
- 双指针:这题和
27.移除元素思路相似,两个指针指向新老两个数组的对应位置,在一个for循环里做了两个循环做的事 - 后序:从后往前修改,避免了从前往后每次插入新元素要整体移动后面的元素,而且最后几个元素为
resize出来的空元素 ntail指向新字符串的需要更新的位置,otail指向旧字符串的检索到的位置- 先扩容再操作
双指针
class Solution {
public:
string replaceSpace(string s) {
int count = 0;
int otail = s.size()-1;
for (int i = 0; i < s.size(); i++){
count = s[i] == ' ' ? count+1 : count;
}
s.resize(s.size() + 2*count);
int ntail = s.size()-1;
for (otail; otail >= 0; otail--) {
if (s[otail] != ' ') s[ntail--] = s[otail];
else {
s[ntail--] = '0';
s[ntail--] = '2';
s[ntail--] = '%';
}
}
return s;
}
};
总结
字符串的resize不改变其capacity大小(默认15),只改变size大小,先扩容将存%20多余字符的空间开出来。
151.反转字符串中的单词
要点
- 先用双指针法清洗一下字符串,将多余的空格舍弃,重新设置
string.size - 再整体反转字符串,单词反转,转回单词正常顺序
双指针 + 反转字符串
class Solution {
public:
void reverse(string& s, int start, int end) {
for (start, end; start < end; start++, end--) {
swap(s[start], s[end]);
}
}
void removeBlank(string& s) {
int slow = 0;
//fast指针去找非空格字符
for (int fast = 0; fast < s.size(); fast++) {
if (s[fast] != ' ') {
s[slow++] = s[fast++];
//填完当前这个单词
while (fast < s.size() && s[fast] != ' ') s[slow++] = s[fast++];
//在单词后补个空格,始终指向新字符串下一个待填的位置
s[slow++] = ' ';
}
}
s.resize(slow-1);
}
string reverseWords(string s) {
removeBlank(s);
reverse(s, 0, s.size()-1);
int i = 0;
for (int j = 0; j <= s.size(); j++) {
//只有快的那个指针遇到空格 或者 到字符串末尾了,才将这个单词再反一下
if (j == s.size() || s[j] == ' ') {
reverse(s, i, j-1);
i = j+1;
}
}
return s;
}
};
总结
这题和上一题的双指针法都有移除元素的味道,快慢指针分别指向新老字符串的对应位置,快指针++写在for循环条件里,循环体里通常只有一个if判断,不满足就fast++找下一个了。
for (int fast = 0; fast < s.size(); fast++) {
if (s[fast] != ' ') {
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
s[slow++] = s[fast++];
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
}
}
清洗字符串和反转字符串子串单词都用到了类似的双指针法
剑指 Offer 58 - II. 左旋转字符串
要点
- 左旋、右旋有点像队列的出队入队
- 先将两个子串反转,再整体反转(反过来也可以,只不过分割点在对称到另一侧了)
双指针
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin()+n);
reverse(s.begin()+n, s.end());
reverse(s.begin(), s.end());
return s;
}
};
总结
右旋同理,本质是两个子串交换一下位置
reverse函数左闭右开,时间复杂度O(n)、空间复杂度O(1)