1. 程式人生 > 其它 >[題解]劍指 Offer 58 - I. 翻轉單詞順序(C++)

[題解]劍指 Offer 58 - I. 翻轉單詞順序(C++)

題目

輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。為簡單起見,標點符號和普通字母一樣處理。例如輸入字串"I am a student. ",則輸出"student. a am I"。

示例 1:

輸入: "the sky is blue"
輸出:"blue is sky the"

示例 2:

輸入: " hello world! "
輸出:"world! hello"
解釋: 輸入字串可以在前面或者後面包含多餘的空格,但是反轉後的字元不能包括。

示例 3:

輸入: "a good  example"
輸出:"example good a"
解釋: 如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。

說明:

  • 無空格字元構成一個單詞。
  • 輸入字串可以在前面或者後面包含多餘的空格,但是反轉後的字元不能包括。
  • 如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

思路

要翻轉單詞的順序同時保持單詞內字元的順序,很自然地想到利用棧先進後出的特性。遍歷s把單詞逐個入棧,然後丟擲單詞直到棧空,記得在首個單詞以外的單詞前面加上空格。
時間複雜度O(n),空間複雜度O(n)。

程式碼

class Solution {
public:
    string reverseWords(string s) {
        stack<string> stk;
        for(int left = 0; left < s.size(); ++left)
        {
            if(s[left] != ' ')
            {
                int right = left;
                while(right < s.size() && s[right] != ' ') right++;
                string tmp(s.begin() + left, s.begin() + right);
                stk.push(tmp);
                left = right;
            }
        }
                        
        string ans = "";
        while(!stk.empty())
        {
            if(!ans.empty()) ans += ' ';
            ans += stk.top();
            stk.pop();
        }
        return ans;
    }
};

改進

用棧解決需要額外O(n)的空間,能不能直接在傳入的s上原地修改?利用c++的翻轉函式reverse(也可以自己實現)可以做到,先翻轉整個字串,然後用雙指標,write指向要寫入的位置,read指向讀到單詞的位置;read讀到單詞時,用wordend向後遍歷到空格或者字串結束,把wordend遍歷到的字元寫到write指向的位置,然後再在新字串離翻轉新寫進來的這個單詞。注意每次寫入單詞前除了首個單詞外要加上空格。
時間複雜度O(n),空間複雜度O(1)。

程式碼

class Solution {
public:
    string reverseWords(string s) {
        reverse(s.begin(), s.end());
        int write = 0, n = s.size();
        for(int read = 0; read < n; ++read)
        {
            if(s[read] != ' ')
            {
                if(write != 0) s[write++] = ' ';
                int wordend = read;
                while(wordend < n && s[wordend] != ' ') s[write++] = s[wordend++];
                reverse(s.begin() + write - (wordend - read), s.begin() + write);
                read = wordend;
            }
        }
        s.erase(s.begin() + write, s.end());
        return s;
    }
};