1. 程式人生 > >leetcode895. 最大頻率堆疊(兩種思路)

leetcode895. 最大頻率堆疊(兩種思路)

題目:

實現 FreqStack,模擬類似棧的資料結構的操作的一個類。

FreqStack 有兩個函式:

  • push(int x),將整數 x 推入棧中。
  • 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]
解釋:
執行六次 .push 操作後,棧自底向上為 [5,7,5,7,4,5]。然後: pop() -> 返回 5,因為 5 是出現頻率最高的。 棧變成 [5,7,5,7,4]。 pop() -> 返回 7,因為 5 和 7 都是頻率最高的,但 7 最接近棧頂。 棧變成 [5,7,5,4]。 pop() -> 返回 5 。 棧變成 [5,7,4]。 pop() -> 返回 4 。 棧變成 [5,7]。

提示:

  • 對 FreqStack.push(int x) 的呼叫中 0 <= x <= 10^9
  • 如果棧的元素數目為零,則保證不會呼叫  FreqStack.pop()
  • 單個測試樣例中,對 FreqStack.push 的總呼叫次數不會超過 10000
  • 單個測試樣例中,對 FreqStack.pop 的總呼叫次數不會超過 10000
  • 所有測試樣例中,對 FreqStack.push 和 FreqStack.pop 的總呼叫次數不會超過 150000

思路1:

本人思路:需要用到:一個優先佇列p,一個map ma,兩個棧q,qu。結構體MY(第一個元素是原數值,第二個元素是該數值出現的頻數)

優先佇列每一個元素都是一個MY,根據頻數由大到小排序,map鍵是原數值,值是該數值出現的實時頻數,佇列用來存放數值

對於每個push操作x:首先map記錄加一,然後把map的值和對應的鍵插入優先佇列。如果優先佇列之前就有這個鍵的MY了也沒有關係,因為ma[x]記載的是x實時的頻數,在取數的時候,如果佇列中MY.頻數!=ma[x]的話,這個記錄肯定是無效的。

對於每個pop:首先找到優先佇列中第一個有效元素,也就是x是MY的第一個元素的情況下,MY第二個元素和ma[x]相同,

找到這個有效MY之後,記錄這個MY出現的頻數ans,這肯定是當前最大的頻數,然後遍歷棧q,直到有一個元素x的當前次數ma[x]等於ans,在遍歷的過程中把元素放到qu中,待到之後再把qu的元素放回去,因為每次只需要刪一個,其他元素需要還原。

程式碼:

class FreqStack {
public:
struct MY{
    int yu,ra;
    MY(){}
    MY(int x,int y):yu(x),ra(y){}
    bool operator<(const MY &m)const{
        return ra<m.ra;
    }
};

priority_queue<MY>p;
map<int,int>ma;
stack<int>q;
 FreqStack() {
    while(!p.empty()){
        p.pop();
    }
    ma.clear();
    while(!q.empty())q.pop();
}

void push(int x) {
    int nu = ma[x] + 1;
    ma[x] = nu;
    p.push(MY(x,nu));
    q.push(x);
}

int pop() {
    int ans = 0,res=0;
    while(!p.empty()){
        MY m = p.top();
        if(ma[m.yu]==m.ra){
            ans = m.ra;
            break;
        }
        p.pop();
    }
    stack<int>qu;
    while(!q.empty()){
        int num = q.top();q.pop();
        if(ma[num]==ans){
            ma[num] = ma[num] - 1;
            res = num;
            break;
        }
        else qu.push(num);
    }
    while(!qu.empty()){
        int num = qu.top();qu.pop();
        q.push(num);
    }
    return res;
}

};

思路2:

還有一種簡單的思路:這個題目有兩個條件,一個要找出現頻率最高的數字,如果只有這一個條件我們可以很簡單的用一個優先佇列對出現頻率排序即可,但是還有一個條件就是在頻率相同的時候,需要找棧裡面比較新的元素,這個條件可以稍微轉變一下,如果我們給每一個入棧的元素一個序號t,後入棧的元素編號肯定大於前面入棧的元素的編號,那麼我們不就可以根據這個編號來判斷入棧的時間了嗎?這樣就可以用一個優先佇列解決了。所以這一題關鍵就在於把棧的順序編號化

程式碼

struct MY{
    int yu,ra,step;
    MY(){}
    MY(int x,int y,int z):yu(x),ra(y),step(z){}
    bool operator<(const MY &m)const{
        if(ra==m.ra)return step<m.step;
        else return ra<m.ra;
    }
};

map<int,int>ma;
priority_queue<MY>p;
int t = 0;
FreqStack() {
    while(!p.empty())p.pop();
    ma.clear();
    t = 0;
}

void push(int x) {
    ma[x] = ma[x] + 1;
    p.push(MY(x,ma[x],t++))
}

int pop() {
    MY my = p.top();
    int x = my.yu;
    ma[x] = ma[x] - 1;
    p.pop();
    return x;
}