Description
有一堆石頭,每塊石頭有正整數重量。每回合選出最重的兩塊石頭互相碰撞:若兩塊一樣重,都消失;若不同,較輕的消失,較重的變成差值。最後剩下的石頭重量是多少?若沒有剩餘則回傳 0。
Example:
Input: stones = [2,7,4,1,8,1] Output: 1
Intuition#
核心思路:每次都要取最大的兩個元素,Max Heap 是天然的選擇。
- 每回合需要最重的兩塊石頭 → 需要高效取最大值的資料結構
- Max Heap 可以 O(1) 取最大值,O(log n) 插入和刪除
- 模擬碰撞過程,直到剩下 0 或 1 塊石頭
Approaches#
1: Sorting Each Round#
- 概念: 每回合排序陣列,取最後兩個元素碰撞,將結果放回陣列
- 時間複雜度:
O(n^2 log n)- 最多 n 回合,每回合排序 O(n log n) - 空間複雜度:
O(n)
class Solution {
fun lastStoneWeight(stones: IntArray): Int {
val list = stones.toMutableList()
while (list.size > 1) {
list.sort()
val first = list.removeAt(list.lastIndex)
val second = list.removeAt(list.lastIndex)
if (first != second) {
list.add(first - second)
}
}
return if (list.isEmpty()) 0 else list[0]
}
}⭐2: Max Heap#
- 概念: 用 Max Heap 存所有石頭,每回合取出最大的兩塊碰撞,若有剩餘則放回 heap
- 時間複雜度:
O(n log n)- 最多 n 回合,每回合 heap 操作 O(log n) - 空間複雜度:
O(n)
class Solution {
fun lastStoneWeight(stones: IntArray): Int {
val maxHeap = PriorityQueue<Int>(compareByDescending { it })
for (s in stones) maxHeap.offer(s)
while (maxHeap.size > 1) {
val first = maxHeap.poll()
val second = maxHeap.poll()
if (first != second) {
maxHeap.offer(first - second)
}
}
return if (maxHeap.isEmpty()) 0 else maxHeap.peek()
}
}🔑 Takeaways#
- Pattern: 反覆取最大/最小值的模擬題,用 Heap 來加速
- 關鍵技巧: Kotlin/Java 的 PriorityQueue 預設是 Min Heap,要 Max Heap 需傳入
compareByDescending { it }或reverseOrder()