《剑指offer》42:翻转单词顺序

这个单元有两道题,都是字符串操作,挺简单的,不过如果没经历过思考的过程,可能就不是那么容易了,简单 != 容易
书里安排了比较简单的左旋字符串在后面,我觉得反了,所以换了顺序来说。

左旋字符串

将一个字符串“左移”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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值