Hard草稿★★★★★O(1) 時間 · O(n) 空間
StackHash MapDesign
Patterns🏗️ 資料結構設計🥞 堆疊#️⃣ 雜湊
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

895Maximum Frequency StackStackHardStack

設計一個類似堆疊的資料結構,支援 pushpop 操作:

  • push(val): 將整數 val 壓入堆疊
  • pop(): 移除並回傳堆疊中頻率最高的元素。若有多個頻率相同的元素,移除最接近棧頂的那個

Example:

Input: [“FreqStack”, “push”, “push”, “push”, “push”, “push”, “push”, “pop”, “pop”, “pop”, “pop”], [[], [5], [7], [5], [7], [4], [5], [], [], [], []] Output: [null, null, null, null, null, null, null, 5, 7, 5, 4]

Intuition

TIP

核心思路:用 HashMap 記錄每個值的頻率,再用「頻率 -> 堆疊」的映射,pop 時從最高頻率的堆疊取出。

Approaches

1. Brute Force: Scan All on Each Pop — O(n) per pop / O(n)
  • Idea: 依 push 順序存進清單;pop 時掃一遍算各值頻率,取頻率最高、同頻取最近 push 的那個
  • Time: push O(1)、pop O(n)
  • Space: O(n)
class FreqStack() {
    private val stack = ArrayList<Int>()   // 依 push 順序

    fun push(`val`: Int) { stack.add(`val`) }

    fun pop(): Int {
        val freq = HashMap<Int, Int>()
        var bestVal = 0; var bestFreq = 0; var bestIdx = -1
        for (i in stack.indices) {
            val f = (freq[stack[i]] ?: 0) + 1
            freq[stack[i]] = f
            if (f >= bestFreq) { bestFreq = f; bestVal = stack[i]; bestIdx = i }  // >= 取最近
        }
        stack.removeAt(bestIdx)
        return bestVal
    }
}
⭐ 2. Frequency-Bucket Stacks — O(1) / O(n)
  • Idea: freqMap 記錄每個值的當前頻率,groupStackMap<Int, Stack>,將每次 push 按頻率分組。維護 maxFreq 追蹤最高頻率
  • Time: push 和 pop 均 O(1)
  • Space: O(n)
class FreqStack() {
    private val freqMap = HashMap<Int, Int>()      // val -> 當前頻率
    private val groupStack = HashMap<Int, ArrayDeque<Int>>() // freq -> stack of vals
    private var maxFreq = 0

    fun push(`val`: Int) {
        val freq = (freqMap[`val`] ?: 0) + 1
        freqMap[`val`] = freq
        maxFreq = maxOf(maxFreq, freq)

        groupStack.getOrPut(freq) { ArrayDeque() }.addLast(`val`)
    }

    fun pop(): Int {
        val stack = groupStack[maxFreq]!!
        val val_ = stack.removeLast()

        freqMap[val_] = freqMap[val_]!! - 1

        if (stack.isEmpty()) {
            groupStack.remove(maxFreq)
            maxFreq--
        }

        return val_
    }
}

WARNING

為什麼 maxFreq-- 是正確的?因為 maxFreq 對應的堆疊為空時,下一個最高頻率一定是 maxFreq - 1(每次 push 頻率只增加 1,所以頻率是連續的,不會跳過)。

🔑 Takeaways