方法一:栈
核心思想
题目要求将单词逆序输出,很容易想到一个思路就是利用栈的先入后出特性。
解法:首先读取单词,以空格为分界符(在字符串最后加上一个空格避免特判),读取的同时进行大小写转换,然后将单词加入到栈中。在全部单词读取完毕后,逐个弹出单词,即为答案
图示:
图片说明
之后从栈顶逐个弹出即为答案
核心代码

class Solution {
public:
    string trans(string s, int n) {
        stack<string> sk;
        string str;
        s.push_back(' ');//避免特判
        for(int i = 0; i <= n; ++i) {//注意此时单词长度为n+1
            if(s[i] == ' ') {
                sk.push(str);//以空格为界进行压栈
                str = ""; 
            } else {
                if(s[i] >= 'a' && s[i] <= 'z') { 
                    str += (s[i] - 'a' + 'A'); 
                } else { 
                    str += (s[i] - 'A' + 'a'); 
                } 
            }
        } 
        string ans; 
        while(!sk.empty()) { 
            //从栈中逐个弹出单词 
            ans += sk.top(); sk.pop(); 
            ans.push_back(' '); 
        } 
        ans.pop_back();//去除最后一个单词后的空格 
        return ans;
    }
};

复杂度分析
时间复杂度:$O(n),$需要对单词进行读取以及弹出,两个操作时间复杂度都为O(n)
空间复杂度:$O(n)$,需要额外的栈空间存储单词,以及存储转换后单词的字符串

方法二:两次翻转
核心思想

题目要求的是按单词进行反序,可以通过两轮翻转实现。第一次将整个字符串翻转,此时每个单词所在位置即为最终位置,但每个单词中的字符顺序是翻转的。第二次将每个单词进行翻转,这样还原了每个单词内字母的原本顺序。在第二次翻转时同时对字母进行大小写转换




核心代码

class Solution {
public:
    string trans(string s, int n) {
         reverse(s.begin(), s.end());//将整个字符串进行翻转
        int i = 0, j = 0;
        while(i < n) { 
            j = i; 
            while(j < n && s[j] != ' ') { 
                //读取一个单词并同时进行大小写转换 
                if(s[j] >= 'a' && s[j] <= 'z') { 
                    s[j] += ('A' - 'a'); 
                } else { 
                    s[j] += ('a' - 'A'); 
                } 
                ++j; 
             }
            reverse(s.begin() + i, s.begin() + j);//翻转这个单词 
            i = j + 1; 
        }
        return s;
    }
};

复杂度分析
时间复杂度:$O(n)$,相对于需要对整个字符串进行两次读取(翻转)
空间复杂度:$O(1)$,只使用了常数个变量