这个单元有两道题,都是字符串操作,挺简单的,不过如果没经历过思考的过程,可能就不是那么容易了,简单 != 容易。
书里安排了比较简单的左旋字符串在后面,我觉得反了,所以换了顺序来说。
左旋字符串
将一个字符串“左移”k位,比如”123456789”左移3位变成”456789123”。
最笨的方法
逐个向左移动,比如123456789->234567891->345678912->…
每次移动的时间复杂度都是O(n),总的复杂度就是O(kn),k最多可以为n-1,所以复杂度最坏可达到O(n^2)!
假设k=3,则需要把”123456789”->”456789123”。看仔细一下,其实是把字符串分成两部分,”123”和”456789”,想把它们两个交换位置而已!
两部分的长度不一样,否则就可以简单地交换了。
不妨先反转整个字符串一遍:987654321。
可以发现,两部分已经到了它们所需要到的位置了,123到了末端,456789到了开头,只不过它们现在都是反转过来了而已,只需要各自再反转一遍就可以了!!!
最后,要注意处理一下,k = k % str.size()
,然后看k等于0的话,就不用处理了,原因就不多说了~应该挺明显的
#include <iostream>
#include <string>
using namespace std;
void reverseHelper(string& str, int beg, int end) {
for (int i = beg, j = end; i < j; ++i, --j)
swap(str[i], str[j]);
}
void reverseWord(string& str, int k) {
int len = str.size();
k = k % len;
if (k > 0) {
reverseHelper(str, 0, k-1);
reverseHelper(str, k, len-1);
reverseHelper(str, 0, len-1);
}
}
int main() {
string str = "hi jacket";
reverseWord(str, 2);
cout << "Finally, str=" << str << endl;
return 0;
}
翻转单词顺序
把一个句子的单词为A B C …,变为… C B A,比如”hello world”变为”world hello”,而”I am a student.”变为”student. a am I”,也就是说,标点符号跟随它前一个单词在一起。
要求:用O(1)的空间和O(n)的时间。
其实原理跟上面的是一样的,只是单词的数量多了,需要用空格将彼此区分开而已~
#include <iostream>
#include <string>
using namespace std;
void reverseHelper(string& str, int beg, int end) {
for (int i = beg, j = end; i < j; ++i, --j)
swap(str[i], str[j]);
}
void reverseSentence(string& str) {
int len = str.size(), i = -1, last = 0;
reverseHelper(str, 0, len-1);
while (++i <= len) {
// 这是我目前能想到的最优美的写法了!!!
if (i == len || str[i] == ' ') {
reverseHelper(str, last, i-1);
last = i + 1;
}
}
}
int main() {
string str = "I am a student.";
reverseSentence(str);
cout << "Finally, str=" << str << endl;
return 0;
}