LeetCode之路:541. Reverse String II

来源:互联网 发布:设置网络位置选哪个好 编辑:程序博客网 时间:2024/05/22 04:27

一、引言

提到 Rerverse,你就要想起来 C++ 的逆置元操作:

std::reverse

这个函数的作用,是将指定容器的指定范围内的元素进行逆置处理。

而这道题就将用到这最基本的逆置元操作。

先看看题目吧:

Given a string and an integer k, you need to reverse the first k characters for every 2k characters counting from the start of the string. If there are less than k characters left, reverse all of them. If there are less than 2k but greater than or equal to k characters, then reverse the first k characters and left the other as original.

Example:
Input: s = “abcdefg”, k = 2
Output: “bacdfeg”

Restrictions:
1.The stirng consists of lower English letters only.
2.Length of the given string and k will in the range [1, 10000]

简单翻译下:

给定一个字符串和一个数字 k,你需要将每个 2k 字符中的前 k 个字符逆置。如果有剩余的 k 以内位数的字符剩余,将它们全部逆置。如果有大于等于 k 位数的字符剩余,则将其第一个 k 位字符全部逆置。

这道题的题意或许读起来不是那么清楚,我这里画了一个简单的图来帮助理解:

Analysis

如果清楚了这道题的意义,让我们开始想想这道题如何解决吧。

二、T_T:一系列的尝试

从这里开始,我开始了三个方法的尝试,分别写了三个不同的方法。

第一个方法:

以 k 为增量遍历字符串,当计数 i 余 2k 等于 k 的时候(也就是遍历到 k 的奇数位的时候),此时将前面 k 位逆置;当退出循环后,需要处理后面的剩余字符,此时首先需要判断 k 与 s 的长度比较,如果 s 的长度小于等于 k,则直接将 s 全部逆置即可;否则的话,判断 i (当前的 i 已经有了 k 的多余递增)余 2k 是否能够剩余 k,如果可以的话,则证明 s 剩余的字符总数小于 k ,此时应该将剩余的全部逆置。

// my first solution1 , rutnime = 6 msclass Solution1 {public:    string reverseStr(string s, int k) {        int i = 0;        for (; i < s.size(); i += k)            if (i % (2 * k) == k) reverse(s.begin() + i - k, s.begin() + i);        if (k >= s.size())            reverse(s.begin(), s.end());        else if (i % (2 * k) == k)            reverse(s.begin() + i - k, s.end());        return s;    }};

可见,这个方法的逻辑比较复杂,此时我考虑是不是以 2k 为递增变量能够简化逻辑:

第二个方法:

以 2k 为增量遍历字符串,每次都将前 k 位递增即可;退出循环则证明剩余了一些字符,此时判断剩余字符的个数是否小于等于 k,如果小于等于 k 位,则全部逆置即可,否则只逆置 k 位数。

// my solutin 2 , runtime = 9 msclass Solution2 {public:    string reverseStr(string s, int k) {        int i = 2 * k;        for (; i < s.size(); i += 2 * k)            reverse(s.begin() + i - 2 * k, s.begin() + i - k);        if (s.size() - (i - 2 * k) <= k)            reverse(s.begin() + i - 2 * k, s.end());        else            reverse(s.begin() + i - 2 * k, s.begin() + i - k);        return s;    }};

计算剩余字符的个数除了使用减法,还可以使用 s 的长度余 2k 来计算,计算余的值与 k 的大小比较:

第三个方法:

使用 s 的长度余 2k 的结果判断剩余字符的处理

// my solution 3 , runtime = 6 msclass Solution3 {public:    string reverseStr(string s, int k) {        int i = 2 * k;        for (; i < s.size(); i += 2 * k)            reverse(s.begin() + i - 2 * k, s.begin() + i - k);        if (s.size() % (2 * k) <= k && s.size() % (2 * k) != 0)            reverse(s.begin() + i - 2 * k, s.end());        else            reverse(s.begin() + i - 2 * k, s.begin() + i - k);        return s;    }};

这里特别处理了 s 余 2k 为 0 的情况。

可见,上述三个方法都难免逻辑复杂。

那么有没有更加优雅的方法呢?

三、One line C++: 最高票答案的启发

此时我点开了 Discuss,看到了高票答案的标题 One line C++,此时此刻,我陷入了沉思:

究竟是哪里可以优化呢?

其实很简单,再看看我们引言里的那张图。

规则听上去很复杂,其实简化起来就是一句话:

每 2k 字符逆置前 k 个字符,如果凑不够 k 个字符的,则全部逆置

那么这里就涉及到了当前剩余字符的大小与 k 的比较。

因此,我稍作思考,写下了下列的代码:

// perfect solution 4 , runtime = 6 msclass Solution4 {public:    string reverseStr(string s, int k) {        for (int i = 0; i < s.size(); i += 2 * k) reverse(s.begin() + i, min(s.end(), s.begin() + i + k));        return s;    }};

同样的,也是以 2k 为增量遍历字符串;

不同的,这里使用了 std::min 方法,比较了 std::string::end()std::string::begin() + i + k 的大小比较,其中达到了取最小值的目的。

因此,这道题就这么简单的,以 One line C++(虽然我觉得应该是 Two lines T_T)的形式做出来啦!

至此,完结,撒花!!!

四、总结

这道题重在分析吧,一上手就写代码然后陷入混乱的人必然是分析的不够的。

这道题还是挺有趣的,属于那种自己做花了很长时间很多精力,然后高票答案一行代码就把你噎回去的那种:)

最后的最后,还是以许嵩的《通关》的歌词结尾:

千里江陵一日可还
十年的情要慢慢还
不回味这一路的难
你若是终点我必通关

依然共勉 ^_^