今天的主题是字符串,题目一共有五个,还可以。参考资料:卡哥文献
一、反转字符串:
1、思路:
这一道题我没有多想,第一秒就是想到的是双指针:
(1)一个指针指头,一个指针指向尾部
(2)把指针放到循环中去遍历和交换即可了。
2、代码:
(1)自己写的版本:
void reverseString(vector<char>& s) {
char temp;
int tail = s.size() - 1;
for (int head = 0; head < tail; head++) {
temp = s[head];
s[head] = s[tail];
s[tail] = temp;
tail--;
}
}
时间复杂度是O(n),空间复杂度是O(1),符合题目要求,但是感觉不是很快,我参考了以下卡哥的方法,卡哥的思路和我一样,但是他的方法调用了一个交换的库函数。
(2)卡哥版本:
class Solution {
public:
void reverseString(vector<char>& s) {
// char temp;
int tail = s.size() - 1;
for (int head = 0; head < tail; head++) {
// temp = s[head];
// s[head] = s[tail];
// s[tail] = temp;
swap(s[head], s[tail]);
tail--;
}
}
};
二、反转字符串||
看完题目,就想着用双指针,结果写出来一个bug多多的程序。。
1、错误代码:
string reverseStr(string s, int k) {
if (s.size() < k) {
reverse(s.begin(), s.end());
return s;
}
int tail = 0;
int head = 0;
for (; head < s.size(); head++) {
if ((head + 1) / k == 2) {
int temp = head;
head = head / 2;
while (head > tail) {
swap(s[head], s[tail]);
head--;
tail++;
}
tail = temp + 1;
head = temp + 1;
}
}
if (head - tail >= k) {
head = tail + k - 1;
while (head > tail) {
swap(s[head], s[tail]);
head--;
tail++;
}
} else {
while (head > tail) {
swap(s[head], s[tail]);
head--;
tail++;
}
}
return s;
}
这个代码总是缝缝补补,一直运行不出来
请求了以下GPT教授,帮我改了一下代码,GPT教授太厉害了。
2、修正后代码:
string reverseStr(string s, int k) {
int n = s.size();
for (int i = 0; i < n; i += 2 * k) {
int head = i;
int tail = min(i + k - 1, n - 1);
while (tail > head) {
swap(s[head], s[tail]);
tail--;
head++;
}
}
return s;
}
这里利用了一个很巧妙的tail的取值方法,tail = i+k-1 和 n-1中的较小的一个,这样就可以很方便的判断那个时候到了tail 与 head的差距小于k了,就只需要变动tail的值就可以解决了。
看完卡哥的代码之后,就发现和gpt教授的思路差不多,都是在for循环上面做文章
3、卡哥代码:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += 2 * k) {
if (i + k < s.size()) {
reverse(s.begin() + i, s.begin() + i + k);
} else {
reverse(s.begin() + i, s.end());
}
}
return s;
}
卡哥的反转是利用了库函数的,所以看起来更加的简洁;
三、替换数字
卡哥的网站的题目,有点懵逼,虽然理解题意,但是对c++的数据结构还是不是很清楚,只好看看题解了。
看完之后发现也没有那么离谱,但是这个思想确实值得学习,这就是从后向前开始更替,代码如下
1、代码:
#include<iostream>
using namespace std;
int main() {
string s;
while (cin >> s) {
int count = 0; // 统计数字的个数
int sOldSize = s.size();
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
count++;
}
}
// 扩充字符串s的大小,也就是每个空格替换成"number"之后的大小
s.resize(s.size() + count * 5);
int sNewSize = s.size();
// 从后先前将空格替换为"number"
// 都是从最后开始
// 不是数字就往后移
// 是数字就变为number
for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
if (s[j] > '9' || s[j] < '0') {
s[i] = s[j];
} else {
s[i] = 'r';
s[i - 1] = 'e';
s[i - 2] = 'b';
s[i - 3] = 'm';
s[i - 4] = 'u';
s[i - 5] = 'n';
// 更新i的数值
i -= 5;
}
}
cout << s << endl;
}
}
照着卡哥的代码写了一遍,感觉是有收获的。
四、反转字符串中的单词
1、思路:
(1)去掉多余的空格
(2)第一步把所有字符串反转
(3)在逐个单词反转
总体来说就这三个函数,实现出来就好了
2、代码:
void reverseStr(string& s, int left, int right) {
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
void DeleteBlank(string& s) {
int fast = 0;
int slow = 0;
while (s[fast] == ' ' && fast < s.size()) {
fast++;
}
for (; fast < s.size(); fast++) {
if (fast - 1 > 0 && s[fast] == ' ' && s[fast - 1] == ' ') {
continue;
}
else {
s[slow++] = s[fast];
}
}
if (slow - 1 > 0 && s[slow - 1] == ' ') {
s.resize(slow - 1);
}
else {
s.resize(slow);
}
}
string reverseWords(string& s) {
DeleteBlank(s);
reverseStr(s, 0, s.size() - 1);
int slow = 0;
for (int fast = 0; fast <= s.size(); fast++) {
if (s[fast] == ' ' || fast == s.size()) {
reverseStr(s, slow, fast - 1);
slow = fast + 1;
}
}
return s;
}
先总体,再局部。
五、右旋字符串
1、思路:
先总体,再局部
2、代码:
#include<iostream>
using namespace std;
void reverse(string &s, int left, int right) {
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
int main() {
string s;
int k;
cin >> k;
cin >> s;
reverse(s, 0, s.size() - 1);
reverse(s, 0, k - 1);
reverse(s, k, s.size() - 1);
cout << s << endl;
return 0;
}
调试了几波,终于过了哈哈哈,明天继续努力!
学习时长两个半小时!