描述

反转单词序列

数据范围:1 <= n <= 100

进阶:空间复杂度O(n),时间复杂度O(n),保证没有只包含空格的字符串

示例:

  • 输入:"nowcoder. a am I"
  • 输出:"I am a nowcoder."

类似题目:字符串变形,反转之后还需要大小写转换

大小写转换方法:

//使用`Character`类方法
    char swapCase1(char c) {
        if(Character.isUpperCase(c)) {
            c = Character.toLowerCase(c);
        } else {
            c = Character.toUpperCase(c);
        }
        return c;
    }
//使用ASCII码计算,效率会高一点
    char swapCase2(char c) {
        if(c >= 'A' && c <= 'Z') {
            c = (char) (c - 'A' + 'a');
        } else {
            c = (char) (c - 'a' + 'A');
        }
        return c;
    }

思路1:split+倒序遍历

split分割之后,倒序遍历数组

public class Solution {
    public String ReverseSentence(String str) {
        String[] arr = str.split(" ");
        StringBuilder sb = new StringBuilder();
        for(int i = arr.length - 1; i >= 0; i--) {
            sb.append(arr[i]);
            if(i != 0) {
                sb.append(" ");
            }
        }
        return sb.toString();
    }
}

思路2:使用栈存储字符

不借助split函数,从末尾遍历将每个字符入栈,遇到空格时全部弹出

public class Solution {
    public String ReverseSentence(String str) {
        Stack<Character> stack = new Stack<>();
        StringBuilder sb = new StringBuilder();
        //从末尾遍历
        for(int i = str.length() - 1; i >= 0; i--) {
            char c = str.charAt(i);
            //使用栈保存每个字符
            if(c != ' ') {
                stack.push(c);
            } else {
                //遇到空格时全部弹出,并补上空格
                while(!stack.isEmpty()) {
                    sb.append(stack.pop());
                }
                sb.append(' ');
            }
        }
        //最后一个单词,不用补空格
        while(!stack.isEmpty()) {
            sb.append(stack.pop());
        }
        return sb.toString();
    }
}

思路3:使用栈存储单词

顺序遍历,拼接字符串,遇到空格,将字符串入栈,最后出栈拼接

示例:Stack={"I", "am", "a"},最后一个单词已经在StringBuilder中了,不需要入栈

public class Solution {
    public String ReverseSentence(String str) {
        Stack<String> stack = new Stack<>();
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if(c != ' ') {
                sb.append(c);
            } else {
                stack.push(sb.toString());
                //将字符串清空
                sb.replace(0, sb.length(), "");
            }
        }
        //最后一个单词已经在StringBuilder中了,不需要入栈
        while(!stack.isEmpty()) {
            sb.append(" ");
            sb.append(stack.pop());
        }
        return sb.toString();
    }
}

思路4:双指针

从末尾开始遍历,i指向单词头,j指向单词尾,遇到空格则切割单词

public class Solution {
    public String ReverseSentence(String str) {
        if(str.isEmpty()) {
            return "";
        }
        int i = str.length() - 1;
        //substring的end不包含,因此需要加1
        int j = i + 1;
        StringBuilder sb = new StringBuilder();
        //从后往前遍历
        while(i > 0) {
            char c = str.charAt(i);
            if(c == ' ') {
                //遇到空格,则切割单词
                //i+1跳过单词前的空格
                String s = str.substring(i + 1, j);
                sb.append(s);
                //在单词后面补上空格
                sb.append(' ');
                //j移到空格的位置
                j = i;
            }
            i--;
        }
        //最后一个单词没有空格,直接切割
        sb.append(str.substring(i, j));
        return sb.toString();
    }
}