题目分析:
1.根据题目要求,每次需要反转前 K 个字符;
2.结束时需要判断剩余字符个数是否大于 K 个,若大于 K 则反转前 K 个字符,若小于 K 则反转剩余的所有字符
3.根据题目要求,我们需要不断地反转字符串,进行重复的操作,所以首先想到使用循环解决问题
4.先进行一次字符串反转,再推到整个循环的开始结束条件.
5.由于需要进行字符串反转,而且是在字符串内部进行反转,所以需要反转的位置,从哪里开始,从哪里结束。因此,使用到双指针的思想
具体实现
1.定义两个变量,分别存储反转字符串的左右下标
int l = 0; //指向当前位置
int r = 0; //要交换的位置
int len = s.length();
2.开始进入字符串反转条件判断
(1)当剩余字符少于 K 个时,也就是当 的时候,这个时候剩余的字符数量小于 K ,需要反转剩下的字符串。
用 l 保存反转的起始位置,用 r 保存反转的结束位置
使用 while 循环反转这段字符串
//剩余字符少于k个,反转剩下的链表
if (len - 1 - i < k)
{
l = i;
r = len - 1;
//反转
while (l < r)
{
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
}
(2)当剩余字符大于 K 个,并且小于 2K 个时,也就是 时。需要反转前 K 个字符。
此时的 if 条件为 else if 通过上面的 if 条件已经过滤了 的情况,所以只需要判断此时剩余的字符数量是否小于 2*K
设置 交换位置的起始和终止下标,进入交换
else if(len-1-i<2k)
{
l = i;
r = i + k - 1;
while (l < r)
{
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
}
(3)当不属于前面两种条件时,只剩下一种条件了,即 此时,字符串还可以继续进行反转,字符串未结束
else if(len-1-i<2k)
{
l = i;
r = i + k - 1;
while (l < r)
{
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
}
3.编写 for 循环包含字符串反转操作。
(1)当写完前面三段代码时,可以很清楚的感受到代码十分冗余,特别是 while 循环的部分一模一样的代码使用了三次。
(2)优化代码结构,将三段代码的while循环放在 if -else if-else 语句之后,if 语句就只需要考虑反转条件判断和反转位置设置了。
(3)当我们将while 循环的位置优化之后,可以发现,条件 和 条件的 if 语句中的反转下标位置设置是一样的,那么为什么不将 else if-else语句合并成一条语句呢。
for (int i = 0; i < len;)
{
//剩余字符少于k个,反转剩下的链表
if (len - 1 - i < k)
{
l = i;
r = len - 1;
}
//剩余字符大于k个
else
{
l = i;
r = i + k - 1;
}
while (l < r)
{
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
i = i + 2 * k;
}
4.优化代码结构之后,代码利用效率就大大提高了,而且,我们可以使用 进行结束条件判断,字符串不管如何进行交换,如果没有到达末尾,字符串就会继续进行交换,如果到达了末尾,条件 也会让for 循环跳出。一举两得。
完整代码
class Solution {
public:
string reverseStr(string s, int k)
{
int l = 0; //指向当前位置
int r = l + k - 1; //要交换的位置
int len = s.length();
for (int i = 0; i < len;)
{
//剩余字符少于k个,反转剩下的链表
if (len - 1 - i < k)
{
l = i;
r = len - 1;
}
//剩余字符大于k个
else
{
l = i;
r = i + k - 1;
}
while (l < r)
{
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
i = i + 2 * k;
}
return s;
}
};