1. 程式人生 > 其它 >「雜湊表」最大頻率棧(力扣第895題)

「雜湊表」最大頻率棧(力扣第895題)

本題為11月30日力扣每日一題

題目來源:力扣第895題

題目tag:雜湊表

題面

題目描述

設計一個類似堆疊的資料結構,將元素推入堆疊,並從堆疊中彈出出現頻率最高的元素。

實現 FreqStack 類:

  • FreqStack() 構造一個空的堆疊。
  • void push(int val) 將一個整數 val 壓入棧頂。
  • int pop() 刪除並返回堆疊中出現頻率最高的元素。如果出現頻率最高的元素不只一個,則移除並返回最接近棧頂的元素。

示例

輸入:

["FreqStack","push","push","push","push","push","push","pop","pop","pop","pop"],
[[],[5],[7],[5],[7],[4],[5],[],[],[],[]]

輸出:

[null,null,null,null,null,null,null,5,7,5,4]

解釋:

FreqStack = new FreqStack();
freqStack.push(5); //堆疊為 [5]
freqStack.push(7); //堆疊是 [5,7]
freqStack.push(5); //堆疊是 [5,7,5]
freqStack.push(7); //堆疊是 [5,7,5,7]
freqStack.push(4); //堆疊是 [5,7,5,7,4]
freqStack.push(5); //堆疊是 [5,7,5,7,4,5]
freqStack.pop();   //返回 5 ,因為 5 出現頻率最高。堆疊變成 [5,7,5,7,4]。
freqStack.pop();   //返回 7 ,因為 5 和 7 出現頻率最高,但7最接近頂部。堆疊變成 [5,7,5,4]。
freqStack.pop();   //返回 5 ,因為 5 出現頻率最高。堆疊變成 [5,7,4]。
freqStack.pop();   //返回 4 ,因為 4, 5 和 7 出現頻率最高,但 4 是最接近頂部的。堆疊變成 [5,7]。

提示

0 <= val <= $ 10^9 $

push 和 pop 的運算元不大於 $ 2 * 10^4 $。

輸入保證在呼叫 pop 之前堆疊中至少有一個元素。


思路分析

就我個人而言,當我看到題目要實現一個最大頻率棧的時候,我的第一反應是使用單調棧來解決(只是第一反應).而要維護這樣一個單調棧,就需要能在常數時間中取得當前元素的頻率

而每次在常數時間中取得當前元素的頻率這件事,顯然只需要將元素作為鍵,將出現頻率作為值,利用雜湊表就可以完成了.想到這裡我突然發現彈出最大頻率元素也可以用雜湊表就可以直接解決了.

我們只需要維護一個雜湊表,它以出現頻率為鍵,以這個頻率所有元素組成的

為值(其實就是一組棧啦,只是借用了雜湊表的邊長儲存和快速查詢而已),在維護一個儲存最大頻率的變數,就可以實現每次彈出最大頻率的元素啦!

或許這題的難點也在這裡,資料的物理結構邏輯結構並不需要完全對應,甚至可以完全不一樣.因為對外來說,內部的結構都是不可見的,所以只需要能完成指定的行為即可,無需拘泥於特定的形式.

參考程式碼

class FreqStack
{
private:
    // 最大頻率
    int maxFreq;

    // 記錄各個數頻率用的桶
    unordered_map<int, int> book;

    // 每個頻率對應的元素組成的各個棧的集合
    unordered_map<int, stack<int>> bucket;

public:
    /*
        初始化物件

        在C++中此處只需要初始化最大頻率屬性即可
    */
    FreqStack()
    {
        maxFreq = 0;
    }

    /*
        元素入棧
    */
    void push(int val)
    {
        book[val]++; // 更新當前元素出現頻率
        bucket[book[val]].push(val); // 將元素推入對應頻率的棧中
        maxFreq = max(maxFreq, book[val]); // 更新最大頻率
    }

    int pop()
    {
        // 取出最大頻率對應的棧頂元素
        int res = bucket[maxFreq].top();
        bucket[maxFreq].pop();

        // 料理後事
        book[res]--;
        if (bucket[maxFreq].empty()) // 如果空了,手動減小最大頻率
        {
            maxFreq--;
        }

        return res;
    }
};

/**
 * Your FreqStack object will be instantiated and called as such:
 * FreqStack* obj = new FreqStack();
 * obj->push(val);
 * int param_2 = obj->pop();
 */

"正是我們每天反覆做的事情,最終造就了我們,優秀不是一種行為,而是一種習慣" ---亞里士多德