链接:0344.反转字符串
思路:从数组的两端开始,两两交换元素。这里使用闭区间,循环判断使用<
class Solution {
public:
void reverseString(vector& s)
{
if (s.empty()) {
return;
}
size_t left = 0;
size_t right = s.size() - 1;
while (left < right) {
char t = s[left];
s[left] = s[right];
s[right] = t;
++left;
--right;
}
}
};
链接:0541.反转字符串II
思路:每次反转多少字符,反转的左右区间是什么,是由剩余字符串长度决定的。即每次反转之前,需要判断当前i开始往后的字符串的长度,然后再决定反转区间。
每次反转过后,i+=2k。
class Solution {
public:
string reverseStr(string s, int k)
{
int i = 0;
for (; i < s.size(); i += 2 * k) {
// 先计算剩余字符串长度
// 然后根据剩余字符串长度决定反转多少字符
int num = s.size() - i;
if (num < k) {
reverse(s, i, s.size() - 1);
} else {
reverse(s, i, i + k - 1);
}
}
return s;
}
// 为了让代码逻辑更清晰,将纯反转字符串独立出来
// 接收左闭右闭区间
void reverse(string& s, int left, int right)
{
while (left < right) {
char t = s[left];
s[left] = s[right];
s[right] = t;
++left;
--right;
}
}
};
链接:剑指Offer005.替换空格
思路:将数组扩容至替换后的大小,使用双指针,一个指向旧数组的最后一个元素,另一个指向新数组的最后一个元素。
如果左边的指针指的不是空格,那么直接将其移到新数组位置,两个指针同时前移。
如果左边指针指向空格,那么新数组指针填充"%20"并前移到空位,左指针跳过空格。
知道left到达字符串头或者right追上left时停止。
class Solution {
public:
string replaceSpace(string s)
{
if (s.empty()) {
return s;
}
int cnt = 0;
for (char c : s) {
if (c == ' ') {
++cnt;
}
}
int left = s.size() - 1;
if (cnt > 0) {
s.append(2 * cnt, 'a');
}
int right = s.size() - 1;
while (left >= 0 && right > left) {
if (s[left] != ' ') {
s[right] = s[left];
--left;
--right;
} else {
s[right] = '0';
--right;
s[right] = '2';
--right;
s[right] = '%';
--right;
--left;
}
}
return s;
}
};
链接:0151.反转字符串中的单词
思路:
class Solution {
public:
string reverseWords(string s)
{
// 去除尾部空格
while (s[s.size() - 1] == ' ') {
s.pop_back();
}
// 逆序
reverse(s, 0, s.size() - 1);
// 之前头部空格已经被逆序到尾部,去除空格
while (s[s.size() - 1] == ' ') {
s.pop_back();
}
// 分单词逆序
for (int i = 0; i < s.size(); ++i) {
if (s[i] == ' ') {
continue;
}
int j = i + 1;
for (; j < s.size(); ++j) {
if (s[j] == ' ') {
break;
}
}
reverse(s, i, j - 1);
i = j;
}
// 去重中间冗余空格
for (int i = 0; i < s.size(); ++i) {
if (s[i] != ' ') {
continue;
}
// 如果i是空格,i+1不是空格,则不需要去除
if (i + 1 < s.size() && s[i + 1] != ' ') {
++i;
continue;
}
++i; // 跳过一个空格
// 寻找空格后第一个不为空格的字符
int j = i + 1;
for (; j < s.size(); ++j) {
if (s[j] != ' ') {
break;
}
}
// 将单词填充到前面的空格中,同时留下来的位置设置为空格
while (j < s.size() && s[j] != ' ') {
s[i] = s[j];
s[j] = ' ';
++i;
++j;
}
// 由于for循环有一个++,因此这里--
--i;
}
// 中间冗余空格去除后,有效字符前移,因此尾部会有空格,去除尾部空格
while (s[s.size() - 1] == ' ') {
s.pop_back();
}
return s;
}
void reverse(string& s, int left, int right)
{
if (right >= s.size()) {
return;
}
while (left < right) {
char t = s[left];
s[left] = s[right];
s[right] = t;
++left;
--right;
}
}
};
链接:剑指Offer058-II.左旋转字符串
思路:这题当时老师交过我们一次,我的印象非常深刻。先逆序前半部分,再逆序后半部分,最后整个逆序,就可以达到效果了。
class Solution {
public:
string reverseLeftWords(string s, int n)
{
// 逆序前半部分
reverse(s, 0, n - 1);
// 逆序后半部分
reverse(s, n, s.size() - 1);
// 整个逆序
reverse(s, 0, s.size() - 1);
return s;
}
void reverse(string& s, int left, int right)
{
if (right >= s.size()) {
return;
}
while (left < right) {
char t = s[left];
s[left] = s[right];
s[right] = t;
++left;
--right;
}
}
};