题目描
输入一个英文句子,翻转句子的单词顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字符一样处理。
例如,“student. a am I”。正确的输出应该是“I am a student.”。
牛客上输入的是字符串,输出也是字符串。


  一种解题思路,也是offer书上的,先翻转整个字符串,再对每个单词翻转。也有利用栈来完成翻转过程的解法。对于空格的处理也会出现新的解法。
  java涉及到字符串操作的可以分成两类,String和(StringBuilder、StringBuffer)两类。因此,选取不同的类的写法不同。可以调用StringBuffer的函数来完成。

解法1:

  使用最原始的方法,两次翻转,并且所有操作自己来。也是书上的写法。先翻转整个字符串,并用两个指针变量记录某个单词的首尾,去寻找空格,当尾部碰到空格,就说明现在记录的范围内的单词需要再翻转,翻转过后,重新维护两个指针。

public class Solution {
    public String ReverseSentence(String str) {
        if (str == null || str.length() == 0)
            return str;
        char[] arr = str.toCharArray();//转换成字符数组
        reverse(arr, 0, arr.length - 1);//先全部翻转一次
        int start = 0;//指向单词第一个字母
        int end = 0;//指向单词最后一个字母
        while (start < arr.length) {
            if (arr[start] == ' ') {
           //如果start指向的是空格,就换下一个,因为指针要指向的是单词。
                start++;
                end++;
            } else if (end == arr.length || arr[end] == ' ') {
            //要么尾部是空格,要么end刚刚超过数组最后一个角标,这两种情况就应该翻转了
            //end之所以会超过最后角标,是因为当最后一个字符不是空格时,会让end++,所以会越界
                reverse(arr, start, end-1);
            //翻转后,应该重新记录下个单词,因此更新end和start。
                end++;
                start = end;//这句和上一句可以写成start = ++end;
            } else {
            //到这里就说明,start指的不是空格,end也指的不是空格,说明是正常单词,end++即可
                end++;
            }    
        }
        return String.valueOf(arr);
    }
    private void reverse(char[] arr, int begin, int end){
        while(begin<end){
           char temp = arr[begin];
           arr[begin] = arr[end];
           arr[end] = temp;
           begin++;
           end--;
        }
    }
}

解法2:

  在调用一些其他库函数来解决问题时,其实是思想偷懒了,让更多的细节让底层自己去实现。所以某些时候会降低效率,考试推荐使用解法1。平常解决问题时怎么舒服怎么来。

public class Solution {
    public String ReverseSentence(String str) {
        StringBuffer sb = new StringBuffer("");
        if(str.length() <= 0 || str.trim().equals("")){//需要将多个空格的情况考虑进来
            return str;
        }
        String[] strSet = str.split(" ");//将一个字符串分成多个后,装数组里,效率没解法1高
        int length = strSet.length;
        for(int i = length-1; i > 0 ;i--){
            sb.append(strSet[i]+" ");//从尾部添加就可以保证顺序颠倒了
        }
        sb.append(strSet[0]);//写在外面是因为最后一个添加的不用添加空格了。
        return sb.toString();
    }
}

解法3:

拓宽视野用

import java.util.Stack;
public class Solution {
    public String ReverseSentence(String str) {
        if(str == null || str.length()==0)
            return str;
        StringBuilder res = new StringBuilder();
        String[] tmp = str.split(" ");//按照空格,将当前一个字符串分成多个字符串
        if(tmp.length==0)//为了防止出现全空格的情况
            return str;
        Stack<String> stack = new Stack<>();
        for(int i=0; i<tmp.length-1; i++) {
            stack.push(tmp[i]);//将整个小字符串都压入栈
            stack.push(" ");//然后加上空格
        }
        stack.push(tmp[tmp.length-1]);//最后一个直接添加,后面不用再加空格
        while(!stack.isEmpty()) {//最后一个都添加了就的准备弹出了。
            res.append(stack.pop());
        }
        return res.toString();
    }
}

总结:还有使用栈的思路,也还蛮有意思的。不过最好能给出较优解,尽量少使用一些库函数,平常做题开阔视野就可以了。