程式碼手記筆錄——優先佇列與單調佇列
阿新 • • 發佈:2022-05-09
優先佇列
優先佇列採用堆結構儲存資料,高優先順序大頂堆。 可以重寫比較器 cmp 設定優先級別。對於基本資料型別,預設為數值大的優先順序高:
// 二者等價,數值大的優先順序高 priority_queue<int> prq; // (1) priority_queue<int, vector<int>, less<int>> prq; // (2) // 二者等價,設定數值小的優先順序高 priority_queue<int, vector<int>, less<int>> prq; // (1) priority_queue<int, vector<int>, cmp> prq; // (2) bool cmp(int &a, int &b) { return a > b; }
對於類物件型別的 cmp 重寫方式如下:
class fruit {
string name;
int price;
friend operator <(fruit &f1, fruit &f2) {
return f1.price < f2.price; // price 數值高優先順序大
// return f1.price > f2.price; // price 數值小優先順序大
}
};
優先佇列適合求區域性最值問題。
經典例題
239 滑動視窗最大值
(1)將視窗內元素放入優先佇列,並每次取隊頭元素即可得到最大值;
(2)刪除不在視窗的隊頭元素,即可保證每次隊頭元素為區域性最大值。
- 時間複雜度分析:每個元素只入隊、出隊一次,故為 O(n)。
- 空間複雜度分析: O(n)
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { priority_queue<pair<int, int>> prq; vector<int> vec; int n = nums.size(), topN, topIdx; for (int i=0; i<k; ++i) prq.push(make_pair(nums[i], i)); vec.push_back(prq.top().first); // 滑動視窗移動啟動時的最大值 for (int i=k; i<n; ++i) { prq.push(make_pair(nums[i], i)); // 若當前優先佇列的最大值不在視窗內,就讓其 pop 掉 while (prq.top().second <= i-k) prq.pop(); vec.push_back(prq.top().first); } return vec; } };
單調佇列
參照:https://blog.51cto.com/u_13281972/2997983
一個序列只有頭尾的資料有變動,需要求該序列的最大值或最小值,可以嘗試使用單調佇列。
經典例題
239 滑動視窗最大值
演算法思想:單調佇列裡存放陣列下標,且保證下標從小到大排序,同時保證下標對應的元素也從小到大排序。佇列裡值大者放前,每指向一元素,就從隊尾入手將佇列裡小於該元素值的資料彈出【隊尾彈出機制保證了下標對應的元素也從小到大排序】。滑動視窗從左向右移動【移動方向保證了下標從小到大排序】。選取最大值時需彈出隊頭以確保落在滑動視窗內【隊頭彈出機制保證了所求最大值落在滑動視窗內】。
- 時間複雜度分析:每個元素只入隊、出隊一次,故為 O(n)。
- 空間複雜度分析:單調佇列元素最多不超過滑動視窗個數,為 O(k)
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq;
vector<int> vec;
for (int i=0; i<k; ++i) {
while (!dq.empty() && nums[dq.back()] <= nums[i])
dq.pop_back();
dq.push_back(i);
}
vec.push_back(nums[dq.front()]);
for (int i=k; i<nums.size(); ++i) {
// 單調佇列每插入一個元素,都將其前面小於它的元素彈出
while (!dq.empty() && nums[dq.back()] <= nums[i])
dq.pop_back();
dq.push_back(i);
// 由於視窗在移動,因此每移動一次,就將不在視窗內的元素彈出
while (dq.front() <= i-k)
dq.pop_front();
vec.push_back(nums[dq.front()]);
}
return vec;
}
};