Reverse Vowels of a String

題目描述

給定字串 s,只反轉其中的母音字母(a, e, i, o, u,含大小寫),其餘字元位置不變。

輸入:s = "hello"
輸出:"holle"

輸入:s = "leetcode"
輸出:"leotcede"

解題思路

1

轉為陣列

字串不可變,呼叫 toCharArray/split 轉為可修改的字元陣列

2

雙指針初始化

left = 0 指向最左端,right = len-1 指向最右端

3

向內移動

left 跳過非母音字元往右走,right 跳過非母音字元往左走,直到各自停在母音上

4

交換

left 和 right 都指向母音時,swap(arr[left], arr[right]),然後 left++ right--

5

回傳

字元陣列用 join 或 new string 轉回字串

程式碼

C#

csharp
public class Solution {
    public string ReverseVowels(string s) {
        var arr = s.ToCharArray();
        var vowels = new HashSet<char>("aeiouAEIOU");
        int left = 0, right = arr.Length - 1;
        while (left < right) {
            while (left < right && !vowels.Contains(arr[left])) left++;
            while (left < right && !vowels.Contains(arr[right])) right--;
            if (left < right) {
                (arr[left], arr[right]) = (arr[right], arr[left]);
                left++;
                right--;
            }
        }
        return new string(arr);
    }
}

TypeScript

typescript
function reverseVowels(s: string): string {
    const arr = s.split("");
    const vowels = new Set("aeiouAEIOU");
    let left = 0, right = arr.length - 1;
    while (left < right) {
        while (left < right && !vowels.has(arr[left])) left++;
        while (left < right && !vowels.has(arr[right])) right--;
        if (left < right) {
            [arr[left], arr[right]] = [arr[right], arr[left]];
            left++;
            right--;
        }
    }
    return arr.join("");
}

Python

python
def reverseVowels(s: str) -> str:
    arr = list(s)
    vowels = set("aeiouAEIOU")
    left, right = 0, len(arr) - 1
    while left < right:
        while left < right and arr[left] not in vowels:
            left += 1
        while left < right and arr[right] not in vowels:
            right -= 1
        if left < right:
            arr[left], arr[right] = arr[right], arr[left]
            left += 1
            right -= 1
    return "".join(arr)

複雜度分析

| | Time | Space | |--|------|-------| | 本解法 | O(n) | O(n) |

left 和 right 合計最多走 n 步(每步至少移動一個指針),所以時間 O(n)。字元陣列複製整個字串,空間 O(n)。

邊界情況

圖解

h e l l o
雙指針搜尋母音
left→e, right→o
找到配對
交換 e ↔ o
完成
h o l l e

圖表展示 "hello" 的處理過程:left 跳過 h 停在 e(index 1),right 從 o 開始就是母音(index 4)。交換後得到 "holle"。此例只有一對母音需要交換,一輪就完成。

進階觀點

💡面試追問

  • 為什麼用 HashSet 而不是 if 判斷? 兩者查找都是 O(1)。HashSet 寫法更簡潔(vowels.Contains(c) vs 一串 || c == 'a' || c == 'e'...),也更容易擴展(加新字元只需修改集合內容)。
  • 如果要反轉子音呢? 完全一樣的雙指針邏輯,只要把 vowels.Contains 改成 !vowels.Contains,跳過母音、停在子音即可。
  • 跟「反轉字串」的關係? 反轉字串是無條件交換所有字元,本題是「條件交換」的變體。雙指針框架相同,差別只在移動指針時是否跳過某些字元。

理解測驗

🤔 雙指針在這題中為什麼有效?

🤔 s = "aA" 的輸出是什麼?

你可能也想看

605. Can Place Flowers151. Reverse Words in a String

按 ← → 鍵切換課程