题目的主要信息:
  • 将一个英文语句以单词为单位逆序排放
  • 所有单词之间用一个空格隔开,没有仅含空格的案例
举一反三:

学习完本题的思路你可以解决如下题目:

JZ31. 栈的压入、弹出序列

方法一:两次反转(推荐使用)

思路:

我们需要的是将单词位置反转,也即是单词内部不变,属于字符串部分反转问题。如果将整个字符串反转,单词位置倒是反转了,但是内部次序也改变了,此时就需要将内部再反转回去,因此两次反转可以解决。

具体做法:

  • step 1:将字符串整体反转。
  • step 2:遍历反转后的字符串,以空格为界限找到一个单词。
  • step 3:将每个单词部分反转。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    //字符串反转函数
    private void reverse(char [] c, int l, int h){
        //双指针反转
        while(l < h)
            swap(c, l++, h--);
    }
    //字符交换函数
    private void swap(char [] c, int l, int h){
        char temp = c[l];
        c[l] = c[h];
        c[h] = temp;
    }
    
    public String ReverseSentence(String str) {
        int n = str.length();
        char[] c = str.toCharArray();
        //第一次整体反转
        reverse(c, 0, n - 1);
        for(int i = 0; i < n; i++){
            int j = i;
            //以空格为界找到一个单词
            while(j < n && c[j] != ' ') 
                j++;
            //将这个单词反转
            reverse(c, i, j - 1); 
            i = j;
        }
        return new String(c);
    }
}

C++实现代码:

class Solution {
public:
    string ReverseSentence(string str) {
        int n = str.length();
        //第一次整体反转
        reverse(str.begin(), str.end()); 
        for(int i = 0; i < n; i++){
            int j = i;
            //以空格为界找到一个单词
            while(j < n && str[j] != ' ') 
                j++;
            //将这个单词反转
            reverse(str.begin() + i, str.begin() + j); 
            i = j;
        }
        return str;
    }
};

Python实现代码:

class Solution:
    def ReverseSentence(self , str: str) -> str:
        #第一次整体反转
        str = str[::-1]
        s = str.split(' ')
        #以空格为界部分反转
        return (' '.join(s[i][::-1] for i in range(len(s))))

复杂度分析:

  • 时间复杂度:O(n)O(n)nn为整个句子字符串的长度,遍历整个字符串和反转字符串都是O(n)O(n)
  • 空间复杂度:O(1)O(1),常数级变量,无额外辅助空间(其中java版本有O(n)O(n)的辅助空间)
方法二:栈(扩展思路)

知识点:栈

栈是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底。元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;元素出栈指的是从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

思路:

我们都知道栈是先进后出的,于是我们可以用方法一中分割单词的方式,在大的句子字符串中分割出一个一个地单词。然后从头到尾遍历单词,将分割出来的单词送入栈中,然后按照栈中弹出的字符串顺序拼接单词即可使单词之间逆序。

具体做法:

  • step 1:遍历字符串,将整个字符串按照空格分割然后入栈。
  • step 2:遍历栈,将栈中内容弹出拼接成字符串。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    public String ReverseSentence(String str) {
        Stack<String> st = new Stack<String>();
        String[] temp = str.split(" ");
        //单词加入栈中
        for(int i = 0; i < temp.length; i++){
            st.push(temp[i]);
            st.push(" ");
        }
        StringBuilder res = new StringBuilder();
        //去掉最后一个空格
        if(!st.isEmpty())
            st.pop();
        //栈遵循先进后厨,单词顺序是反的
        while(!st.isEmpty())
            res.append(st.pop());
        return res.toString();
    }
}

C++实现代码:

class Solution {
public:
    string ReverseSentence(string str) {
        int n = str.length();
        stack<string> st;
        //遍历字符串,找到单词并入栈
        for(int i = 0; i < n; i++){ 
            int j = i;
            //以空格为界,分割单词
            while(j < n && str[j] != ' ')  
                j++;
            //单词进栈
            st.push(str.substr(i, j - i));  
            i = j;
        }
        str = "";
        //栈遵循先进后厨,单词顺序是反的
        while(!st.empty()){   
            str += st.top();
            st.pop();
            if(!st.empty())
                str += " ";
        }
        return str;
    }
};

Python实现代码:

class Solution:
    def ReverseSentence(self , str: str) -> str:
        #按照空格分开
        strs = str.split(" ")
        st = []
        #入栈
        for s in strs:
            st.append(s)
        res = []
        #出栈逆序
        while len(st) > 0:
            res.append(st.pop())
        #拼接
        return " ".join([x for x in res])

复杂度分析:

  • 时间复杂度:O(n)O(n)nn为整个句子字符串的长度,遍历整个字符串和弹出栈都是O(n)O(n)
  • 空间复杂度:O(n)O(n),栈空最坏情况下长度为nn