编程题是有一个循序渐进的提升过程,很多时候复杂的问题蕴含着基础的问题的解决方式,这个题目有以下的难度提升过程:

交换一个数组中的任意位置的2个元素 -> 翻转一个字符串 -> 翻转单词序列。

在完整翻转一个给定的字符串的时候,双指针从两头向中间夹,依次交换元素;

到了翻转单词序列的时候,就变成了先把整个字符串翻转一遍,再把其中的每个单词(不含空格)再依次翻转一遍。

实现起来就是:

public class Solution {
    public String ReverseSentence(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }
        char[] origin = str.toCharArray();
        reverse(origin, 0, origin.length - 1);
        for (int i = 0; i < origin.length; ++i) {
            if (origin[i] != ' ') {
                int j = i;
                while (j < origin.length) {
                    if (origin[j] == ' ') {
                        break;
                    }
                    ++j;
                }
                reverse(origin, i, j - 1);
                i = j;
            }
        }
        return new String(origin);
    }

    private void reverse(char[] a, int l, int r) {
        while (r > l) {
            swap(a, l++, r--);
        }
    }

    private void swap(char[] a, int x, int y) {
        char tmp = a[x];
        a[x] = a[y];
        a[y] = tmp;
    }
}

但是,由于本题中的单词之间的分割字符只有空格,Java提供了String#split方法可以按照指定的字符进行分割,将一个字符串分割成字符串数组,那么这个题目是否可以先以' '空格进行分割,然后倒序拼接起来呢?以下是一个这样思路的提交:

public class Solution {
    public String ReverseSentence(String str) {
        String[] strList = str.split(" ");
        String result = "";
        for(int i = strList.length - 1; i >= 0; --i) {
            result += " " + strList[i];
        }
        return result.substring(1);
    }
}

这个提交是能够AC的,思路很清晰,实现很简单,而且速度还不慢,但是能够AC就是正确的吗,如果我们自测输入一个案例:

" abc.  "

在单词abc.的左侧有1个空格,右侧有2个空格,上面这种解法的结果是:

"abc. "

很明显,原先的末尾的空格丢失了,而题目是没有说明要对开头或者结尾的空格进行清理的,因此数据丢失。

出现这个问题的原因在于没把握Java中String#split方法的特性,当然牛客的题目并没有表述清楚同时案例过少,Java中当一个字符串以split指定的分隔符结尾时,不论末尾有多少个连续的指定分隔符,Java都会将其忽略。由于牛客的判卷案例较少,因此这个提交也能AC。

当然,考虑到多余空格的处理问题之后,这种解法无疑可以快速解决问题,这就说明了同一个编程题目其实对于不同的语言可能具有不同的难度,高级编程语言的类库对于低级语言而言可能是降维打击。

不同语言提供不同的类库,更高级的编程语言甚至可以直接将这种功能封装成标准方法,但是使用类库的时候务必掌握类库的真实特性,在工业编码中才能真正开发出高质量的代码。