解題說明
Smallest Number in Infinite Set
題目描述:設計一個類別,初始時包含所有正整數 {1, 2, 3, ...}。支援兩種操作:popSmallest() 移除並回傳集合中的最小值;addBack(num) 將 num 加回集合(若已在集合中則忽略)。
解題思路:維護一個變數 currentMin 代表「連續序列的起始點」,初始為 1。另外用一個最小堆(priority_queue min-heap)和一個雜湊集合記錄被加回的數字。popSmallest() 時:若 heap 非空且堆頂 < currentMin,取堆頂;否則取 currentMin 並遞增。addBack(num) 時:若 num < currentMin 且不在 heap 中,則加入 heap 和集合。
C++ 解法
複雜度分析
時間複雜度:popSmallest() O(log k),addBack() O(log k),其中 k 為 heap 中已加回的元素數量,最多為操作次數。
空間複雜度:O(k) — heap 和雜湊集合共存儲最多 k 個加回的元素。
虛擬碼
1. Initialize currentMin = 1, minHeap (min-heap), inHeap (hash set)
2. popSmallest():
a. If minHeap not empty AND minHeap.top() < currentMin:
- Remove and return heap top; erase from inHeap
b. Else: return currentMin++
3. addBack(num):
a. If num < currentMin AND num not in inHeap:
- Push num to minHeap; insert into inHeap其他解法
有序集合(std::set):用 set<int> 儲存被加回的數,begin() 即最小值,O(log n) 的插入和刪除。功能與 min-heap + hash set 相當,但程式碼更簡潔(set 自動去重)。
位元陣列(固定上限):若知道 num 最大值(如 1000),可用 bool 陣列 removed[1001] 標記哪些已被移除,popSmallest() 線性掃描找第一個未移除的。簡單但掃描最壞 O(n)。
延伸思考
- 如果
addBack的次數非常多,heap 會持續成長。如何設計 GC 策略清理不再需要的元素? - 若要同時支援
popLargest()操作(移除最大值),資料結構應如何調整? - 這個設計模式(currentMin + heap for added-back elements)適用於哪些其他場景?