堆(Heap)与优先队列

堆的基础知识

可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组

  • 大顶堆:每个结点的值都大于或等于其左右孩子结点的值
  • 小顶堆:每个结点的值都小于或等于其左右孩子结点的值

堆排序的口诀

  1. 将堆顶元素与堆尾元素交换
  2. 将此操作看作是堆顶元素弹出操作
  3. 按照头部弹出以后的策略调整堆

堆-优先队列

普通队列(最大/最小)堆
尾部入队尾部可以插入
头部出队列头部可以弹出
先进先出每次出队权值(最大/最小的元素)
数组实现数组实现,逻辑上看成一个堆

实现

#define MAX_N 1000;
int data[MAX_N + 5], cnt = 0;
void shift_up(int ind){
	while(ind && data[(ind - 1)/2] < data[ind]){
		swap(data[(ind - 1)/2], data[ind]);
		ind = (ind - 1)/2;
	}
	return;
}
void shift_down(int ind){
	int n = cnt - 1;
	while(ind * 2 + 1 <= n){
		int tamp = ind;
		if(data[temp] < data[ind * 2]+1) temp = ind * 2 + 1;
		if(ind * 2 + 2 <= n && data[temp] < data[ind * 2 + 2]) temp = ind * 2 + 2;
		if(temp == ind) break;
		swap(data[temp], data[ind]);
		ind = temp;
	}
	return
}
void push(int x){
	data[cnt++] = x;
	shift_up(cnt - 1);
	return;
}
void pop(){
	if(size() == 0) return;
	swap(data[0], data[cnt - 1]);
	cnt -= 1;
	shift_down(0);
	return;
}
int top(){
	return data[0];
}
int size(){
	return cnt;
}
int main(){
	int op, val;
	while(cin >> op){
		switch(op){
			case 0: cin>>val; printf("push %d to head \n"); push(val); break;
			case 1: printf("pop %d from heap \n", top()); pop(); break;
		}
	}
	return 0;
}
template<typename T>
class Heap : public vector<T>{
    public:
        template<typename Func_T>
        Heap(Func_T cmp) : cmp(cmp) {}
        void push(const T &a){
            this->push_back(a);
            push_heap(this->begin(), this->end(), cmp);
            return ;
        }
        void pop(){
            pop_heap(this->begin(), this->end(), cmp);
            this->pop_back();
            return ;
        }
        T &top() {return this->at(0); }
    private:
         function<bool(T, T)> cmp;
};

一句话理解堆
堆适合维护:集合最值

经典面试题 - 堆的基础应用

剑指 Offer 40. 最小的k个数

class Solution {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            void pop(){
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ;
            }
            T &top() {return this->at(0); }
            private:
                function<bool(T, T)> cmp;
    };

    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        Heap<int> h{less<int>()};
        for(auto x: arr){
            h.push(x);
            if(h.size() > k) h.pop();
        }
        return h;
    }
};

1046. 最后一块石头的重量

class Solution {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            void pop(){
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ;
            }
            T &top() {return this->at(0); }
            private:
                function<bool(T, T)> cmp;
    };
    int lastStoneWeight(vector<int>& stones) {
        Heap<int> h{less<int>()};
        for(auto x: stones){
            h.push(x);
        }
        while(h.size() > 1){
            int y = h.top(); h.pop();
            int x = h.top(); h.pop();
            if(x == y) continue;
            h.push(y - x);
        }
        if(h.size() == 0) return 0;
        return h.top();
    }
};

703.数据流中的第k大元素

class KthLargest {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            void pop(){
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ;
            }
            T &top() {return this->at(0); }
        private:
            function<bool(T, T)> cmp;
    };
    
    Heap<int> h{greater<int>()};
    int k;
    KthLargest(int k, vector<int>& nums) :k(k) {
        for(auto x: nums){
            add(x);
        }
        return;
    }
    
    int add(int val) {
        h.push(val);
        if(h.size() > k) h.pop();
        return h.top();
    }
};

215.数组中的第k个最大元素

class Solution {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            void pop(){
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ;
            }
            T &top() {return this->at(0); }
        private:
            function<bool(T, T)> cmp;
    };

    int findKthLargest(vector<int>& nums, int k) {
        Heap<int> h{greater<int>()};
        for(auto x: nums){
            h.push(x);
            if(h.size() > k) h.pop();
        }
        return h.top();
    }
};

692. 前K个高频单词

class Solution {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            void pop(){
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ;
            }
            T &top() {return this->at(0); }
        private:
            function<bool(T, T)> cmp;
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string, int> freq;
        for(auto x: words) freq[x] += 1;
        auto cmp = [&freq](string a, string b) ->bool {
            if(freq[a] - freq[b]) return freq[a] > freq[b];
            return a < b;
        };
        Heap<string> h{cmp};
        for(auto x: freq){
            h.push(x.first);
            if(h.size() > k) h.pop();
        }
        sort(h.begin(), h.end(), cmp);
        return h;
    }
};

296.数据流的中位数
对顶堆:将数据分为两半,前半段的最后一个是前半段的最大值,后半段的第一个是后半段的最小值,演变成一个小顶堆和一个大顶堆的管理


class MedianFinder {
public:
    template<typename T>
    class Heap : public vector<T>{
        public:
            template<typename Func_T>
            Heap(Func_T cmp) : cmp(cmp) {}
            void push(const T &a){
                this->push_back(a);
                push_heap(this->begin(), this->end(), cmp);
                return ;
            }
            T pop(){
                T ret = top();
                pop_heap(this->begin(), this->end(), cmp);
                this->pop_back();
                return ret;
            }
            T &top() {return this->at(0); }
        private:
            function<bool(T, T)> cmp;
    };

    Heap<int> h1, h2;
    MedianFinder() : h1{less<int>()}, h2{greater<int>()}{}
    
    void addNum(int num) {
        if(h1.size() == 0 || num <= h1.top()){
            h1.push(num);
        }else{
            h2.push(num);
        }
        if(h2.size() > h1.size()){
            h1.push(h2.pop());
        }
        if(h1.size() == h2.size() + 2){
            h2.push(h1.pop());
        }
        return;
    }
    
    double findMedian() {
        int n = h1.size() + h2.size();
        if(n %2 == 1){
            return h1.top();
        }
        return 1.0 * (h1.top() + h2.top()) / 2;
    }
};

264.丑数ii

class Solution {
public:
    template<typename T>
        class Heap : public vector<T>{
            public:
                template<typename Func_T>
                Heap(Func_T cmp) : cmp(cmp) {}
                void push(const T &a){
                    this->push_back(a);
                    push_heap(this->begin(), this->end(), cmp);
                    return ;
                }
                void pop(){
                    pop_heap(this->begin(), this->end(), cmp);
                    this->pop_back();
                    return ;
                }
                T &top() {return this->at(0); }
            private:
                function<bool(T, T)> cmp;
    };
    int nthUglyNumber(int n) {
        Heap<long long> h{greater<long long>()};
        long long ans = 0;
        h.push(1);
        while(n--){
            ans = h.top();
            h.pop();
            if(ans % 5 == 0){
                h.push(ans * 5);
            }else if(ans % 3 == 0){
                h.push(ans * 5);
                h.push(ans * 3);
            }else{
                h.push(ans * 5);
                h.push(ans * 3);
                h.push(ans * 2);
            }
        }
        return ans;    
    }
};

1753.移除石子的最大得分

class Solution {
public:
    int maximumScore(int a, int b, int c) {
        if (a > b) swap(a, b);
        if (a > c) swap(a, c);
        if (b > c) swap(b, c);
        int ans = 0;
        // step1
        int cnt1 = min(c - b, a);
        a -= cnt1;
        c -= cnt1;
        ans += cnt1;

        // step2
        if(a != 0){
            if(a % 2 == 1) a -= 1;
            b -= a / 2;
            c -= b / 2;
            ans += a;
        }

        // step3
        ans += b;
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值