一、Leetcode第344题:反转字符串
思路:可以发现,无论是字符数组的大小是奇数还是偶数,首尾元素调换的次数都是 s.size() / 2,那么直接一个for循环就可以搞定!元素交换时可以用swap!
class Solution {
public:
void reverseString(vector<char>& s) {
int n = s.size(); // 字符数组长度
for(int ii = 0; ii < (n/2); ii++) { // 无论奇数还是偶数 交换次数都是一样的,都是 n/2 舍弃小数
swap(s[ii], s[n-1-ii]);
// char tmp = s[ii];
// s[ii] = s[n - 1 - ii]; // 注意下标边界为 n - 1
// s[n - 1 -ii] = tmp;
}
}
};
也可以直接调用reverse函数:
// 直接调用reverse函数
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(), s.end());
}
};
也可以像随想录一样使用双指针:
// 使用双指针
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
swap(s[i],s[j]);
}
}
};
二、Leetcode第541题:反转字符串||
思路:一开始想着先把正常情况即 剩余字符大于2k个 时进行单独处理,再处理两种特殊情况,于是代码写的又臭又长!代码如下:
class Solution {
public:
string reverseStr(string s, int k) {
int n = s.size(); // 定义n为数组总长度,在后面循环中会用到
int left = 0; // 左指针
int right = left + k - 1; // 右指针
int nums = 0; // 用于记录 “计数” 了多少次
// 正常计数,即剩余字符大于2k个
while(n >= 2*k) {
// 交换字符 注意终止条件为 ii < jj或(left+right+1)/2!后面的也是如此,可以多试几次!
for(int ii = left, jj = right; ii < (left + right + 1)/2; ii++, jj--) {
swap(s[ii], s[jj]);
}
n -= 2*k; // 更新剩余字符数量
nums++;
left = nums*2*k; // 更新左指针
right = left + k - 1; // 更新右指针
}
// 之前调试时的两种特殊情况,即剩余字符=1 和 k大于剩余字符数量, 后来发现不需要
// if(s.size()-left == 1) return s;
// if(k >= s.size()-left) {
// for(int ii = left, jj = s.size()-1; ii < (left + s.size())/2; ii++, jj--) {
// swap(s[ii], s[jj]);
// }
// return s;
// }
// 如果剩余字符少于 k 个,则将剩余字符全部反转。
if(s.size()-left < k) {
for(int ii = left, jj = s.size() - 1; ii < (s.size() + left)/2; ii++, jj--) {
swap(s[ii], s[jj]);
}
return s;
}
// 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
else if(s.size()-left >= k && s.size()-left < 2*k) {
for(int ii = left, jj = right; ii < (left + right + 1)/2; ii++, jj--) {
swap(s[ii], s[jj]);
}
}
return s;
}
};
这代码写的真差劲!把for循环中的反转封装了一下(也可以直接用reverse),好看一丢丢了:
class Solution {
public:
// 自定义反转reverse
void myreverse(string& s, int left, int right) {
for(int ii = left, jj = right; ii < jj; ii++, jj--) {
swap(s[ii], s[jj]);
}
}
string reverseStr(string s, int k) {
int n = s.size(); // 定义n为数组总长度,在后面循环中会用到
int left = 0; // 左指针
int right = left + k - 1; // 右指针
int nums = 0; // 用于记录 “计数” 了多少次
// 正常计数,即剩余字符大于2k个
while(n >= 2*k) {
// 交换字符 注意终止条件为 (left+right+1)/2 或者直接 ii < jj!后面的也是如此,可以多试几次!
myreverse(s, left, right);
n -= 2*k; // 更新剩余字符数量
nums++;
left = nums*2*k; // 更新左指针
right = left + k - 1; // 更新右指针
}
// 如果剩余字符少于 k 个,则将剩余字符全部反转。
if(s.size()-left < k) {
myreverse(s, left, s.size() - 1);
}
// 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
else if(s.size()-left >= k && s.size()-left < 2*k) {
myreverse(s, left, right);
}
return s;
}
};
看了随想录的解法,发现只要剩余字符大于等于k个,都是将剩余字符的前k个字符进行反转!这样就可以把程序放入一个 for循环中,单独处理剩余字符小于k个的情况就可以了!代码如下:
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s.begin() + i, s.begin() + i + k );
} else {
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s.begin() + i, s.end());
}
}
return s;
}
};
代码是真的简洁呀!以后思考问题一定得多想想,找最简单的解法!!!