class Solution {
public:
    string trans(string s, int n) {
        if (n == 0) return s;
        
        // 第一步:反转整个字符串
        reverse(s.begin(), s.end());
        
        // 第二步:反转每个单词并改变大小写
        int start = 0;
        for (int i = 0; i <= n; i++) {
            if (i == n || s[i] == ' ') {
                // 反转当前单词
                reverseWordAndToggleCase(s, start, i);
                start = i + 1;
            }
        }
        
        return s;
    }
    
private:
    void reverseWordAndToggleCase(string& s, int start, int end) {
        // 反转单词内部的字符顺序
        int left = start, right = end - 1;
        while (left < right) {
            swap(s[left], s[right]);
            // 交换后分别改变大小写
            s[left] = toggleCase(s[left]);
            s[right] = toggleCase(s[right]);
            left++;
            right--;
        }
        
        // 处理中间字符(当单词长度为奇数时)
        if (left == right) {
            s[left] = toggleCase(s[left]);
        }
    }
    
    char toggleCase(char c) {
        if (c >= 'a' && c <= 'z') {
            return c - 'a' + 'A';
        } else if (c >= 'A' && c <= 'Z') {
            return c - 'A' + 'a';
        }
        return c;
    }
};

核心思想:
整体反转:先反转整个字符串,这样单词顺序就反了,但每个单词内部的字符顺序也反了
单词内部反转:再反转每个单词内部的字符顺序,恢复单词的正确顺序
大小写反转:在处理每个单词时同时反转字符的大小写

为什么这样处理空格正确:
原字符串开头的空格在整体反转后会跑到结尾
原字符串结尾的空格在整体反转后会跑到开头
单词之间的空格在反转过程中位置保持不变
时间复杂度:O(n)