解題說明
Longest Happy String
題目描述:
給定整數 a、b、c,分別代表可使用的 'a'、'b'、'c' 字元數量。構造一個盡可能長的字串,使得不包含 "aaa"、"bbb"、"ccc" 作為子字串(即任何字元不能連續出現三次以上)。
解題思路: 使用貪心策略搭配最大堆。每次優先選擇剩餘數量最多的字元,但若該字元已連續出現兩次,則改選次多的字元。
具體步驟:
- 將三個字元及其剩餘數量放入最大堆。
- 每次從堆中取出數量最多的字元。檢查結果字串末兩個字元是否與它相同:
- 若不同:加入該字元,數量減一,放回堆中。
- 若相同:改取次多的字元,加入後放回堆中。若無次多字元可用,結束。
- 重複直到堆為空或無法再加入任何字元。
C++ 解法
複雜度分析
時間複雜度:O((a + b + c) * log 3) = O(a + b + c) — 每步堆操作 O(log 3) = O(1),共最多 a+b+c 步。
空間複雜度:O(1) — 堆最多 3 個元素(不計輸出字串)。
虛擬碼
1. Insert (count, char) into max-heap for each non-zero count
2. While heap is not empty:
a. Pop top element (cnt1, ch1) with highest count
b. If last two characters of result == ch1:
- If heap is empty, break
- Pop second element (cnt2, ch2)
- Append ch2 to result, decrement cnt2
- Push back (cnt1, ch1) and (cnt2-1, ch2) if > 0
c. Else:
- Append ch1 to result, decrement cnt1
- Push back (cnt1-1, ch1) if > 0
3. Return result其他解法
直接模擬(不用堆):每步比較三個字元的剩餘數量,選擇合法且最多的那個。由於只有三個字元,排序/選擇的成本為 O(1)。邏輯等價但不需要堆的資料結構。
批量放置:每次盡量放兩個最多的字元,再穿插一個次多的字元。可以減少迴圈次數但邏輯較複雜,且需謹慎處理邊界條件。
延伸思考
- 若字元種類不只三個(例如 26 個英文字母),演算法需要什麼調整?
- 若限制改為「任何字元不能連續出現超過 k 次」,如何泛化?
- 若要求字串不僅最長,還要字典序最小,如何修改貪心策略?