【LeetCode】堆 heap(共31題)

連接:https://leetcode.com/tag/heap/html

【23】 Merge k Sorted Lists程序員

【215】 Kth Largest Element in an Array (無序數組中最小/大的K個數)(2018年11月30日第一次複習)面試

給了一個無序數組,可能有重複數字,找到第 k 個最大的元素而且返回這個元素值。算法

題解:直接用直接用個堆保存數組中最大的 K 個數。時間複雜度是 O(NlogK)。api

 1 //時間複雜度是 O(NlogK), 用堆輔助。
 2 class Solution {  3 public:  4     int findKthLargest(vector<int>& nums, int k) {  5         const int n = nums.size();  6         priority_queue<int, vector<int>, greater<int>> pq;  7         for (int i = 0; i < n; ++i) {  8             if (pq.size() < k) {  9  pq.push(nums[i]); 10             } else { 11                 if (pq.top() < nums[i]) { 12  pq.pop(); 13  pq.push(nums[i]); 14  } 15  } 16  } 17         return pq.top(); 18  } 19 };
View Code

本題能夠有 O(N) 的解法,詳見《劍指offer》或者《程序員代碼面試指南》P336數組

作法是quickSelect。網絡

 

【218】 The Skyline Problem(2019年2月5日,算法羣打卡複習)app

給了一個tuple list, 每一個三元組 [a, b, h] 表明一個樓的x軸座標是在[a, b],樓的高度是 h,返回全部樓輪廓的左上角座標。less

題解:用了一個 multiset 來存這個樓是進來仍是出去,若是是進來,就存[a, h], 若是是出去,就存[b, -h]。 而後遍歷這個 multiset,若是這個樓是進來的話,就看當前高度它是否是最高的,若是是,那麼這個點在答案中,若是這個樓是出去的話,先把這個高度刪除,而後看當前這個高度是否是比剩下全部樓都高,若是是,就把當前座標和剩下的最高的樓組成的座標加入答案中。dom

 1 class Solution {
 2 public:
 3     vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
 4         for (auto& b : buildings) {
 5             record.insert(make_pair(b[0], b[2]));
 6             record.insert(make_pair(b[1], -b[2]));
 7         }
 8         vector<pair<int, int>> ret;
 9         for (auto& r : record) {
10             bool entry = r.second > 0 ? true : false;
11             int idx = r.first, h = abs(r.second);
12             // printf("idx = %d, h = %d, entry = %d\n", idx, h, entry);
13             if (entry) {
14                 if (h > getMaxHeight()) {
15                     ret.push_back(make_pair(idx, h));
16                 }
17                 height.insert(h);
18             } else {
19                 auto iter = height.find(h);
20                 height.erase(iter);
21                 if (h > getMaxHeight()) {
22                     ret.push_back(make_pair(idx, getMaxHeight()));
23                 }
24             }
25         } 
26         return ret;
27     }
28     struct kcmp {
29         bool operator() (const pair<int, int>& p1, const pair<int, int>& p2) const {
30             if (p1.first == p2.first) {
31                 return p1.second > p2.second;
32             }
33             return p1.first < p2.first;
34         }
35     };
36     multiset<pair<int, int>, kcmp> record;    
37     multiset<int> height;
38     int getMaxHeight() {
39         if (height.empty()) {return 0;}
40         return *height.rbegin();
41     }
42 };
View Code

 

【239】 Sliding Window Maximum (2019年2月18日複習)(用deque作)

求一個滑動窗口的最大值。

題解:用deque作。單調隊列。一開始還想錯了,須要多跑幾個case驗證一下正確性。時間複雜度是O(N)

 1 class Solution {
 2 public:
 3     // [1  3  -1] -3  5  3  6  7 
 4     // 0 1 2 
 5     vector<int> maxSlidingWindow(vector<int>& nums, int k) {
 6         const int n = nums.size();
 7         deque<int> dq;
 8         vector<int> res;
 9         for (int i = 0; i < n; ++i) {
10             if (!dq.empty() && i - dq.front() >= k) {
11                 dq.pop_front();
12             }
13             while (!dq.empty() && nums[dq.back()] < nums[i]) {
14                 dq.pop_back();
15             }
16             dq.push_back(i);
17             if (i - k + 1 >= 0) {
18                 res.push_back(nums[dq.front()]);
19             }
20         }
21         return res;
22     }
23 };
View Code

 

【253】 Meeting Rooms II

題意是252的升級版,給了一個數組,數組裏面的每一個元素表明一個會議的開始時間和結束時間,問想安排下全部的會議,至少須要多少個會議室。

題解:這個題目在 sort 的分類裏面說過,連接:http://www.javashuo.com/article/p-zyassihu-mr.html 

 

【264】 Ugly Number II

返回第 N 個醜數,醜數的定義是因子只有2 ,3 ,5 的數。

題解:咱們用三根指針指向ans中應該乘2, 3 ,5的位置,而後從中選出最小的元素。

 

 1 class Solution {
 2 public:
 3     int nthUglyNumber(int n) {
 4         vector<int> nums(n, INT_MAX);
 5         nums[0] = 1;
 6         int p1 = 0, p2 = 0, p3 = 0;
 7         for (int i = 1; i < n; ++i) {
 8             int minn = min(nums[p1] * 2, min(nums[p2] * 3, nums[p3] * 5));
 9             if (minn == nums[p1] * 2) {++p1;}
10             if (minn == nums[p2] * 3) {++p2;}
11             if (minn == nums[p3] * 5) {++p3;}
12             nums[i] = minn;
13         }
14         return nums[n-1];
15     }
16 };
View Code

 

 

【295】 Find Median from Data Stream (2018年11月30日,堆的題目)

給了一個數據流,設計api接口,addNum() 用於接收一個數,findMedian() 用於返回數據流的中位數。返回數據流的中位數。

Example:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

題解:這題是今天看算法課看到的一個題,咱們用一個大根堆存儲數據流比較小的一半數字,用一個小根堆存數據流的比較大的一半數字。(這兩個堆的元素個數要麼相等,要麼存小數的那個堆比存大數的那個堆多存一個數。)中位數若是兩個堆元素個數相差 1 ,那麼就返回大根堆的堆頂。否則返回兩個堆頂的平均數。

 1 class MedianFinder {
 2 public:
 3     /** initialize your data structure here. */
 4     MedianFinder() {
 5         
 6     }
 7     void addNum(int num) {
 8         lowhalf.push(num);
 9         int k = lowhalf.top(); lowhalf.pop();
10         highhalf.push(k);
11         if (lowhalf.size() < highhalf.size()) {
12             k = highhalf.top(); highhalf.pop();
13             lowhalf.push(k);
14         }
15         return;
16     }
17     double findMedian() {
18         if (lowhalf.size() == highhalf.size()) {
19             return (double)(lowhalf.top() + highhalf.top()) / 2;
20         }
21         return (double)lowhalf.top();
22     }
23     priority_queue<int, vector<int>, greater<int>> lowhalf;  //小根堆存大的那邊
24     priority_queue<int> highhalf; //大根堆存小的那邊 
25 };
26 
27 /**
28  * Your MedianFinder object will be instantiated and called as such:
29  * MedianFinder obj = new MedianFinder();
30  * obj.addNum(num);
31  * double param_2 = obj.findMedian();
32  */
View Code

 

【313】 Super Ugly Number (2019年2月9日,heap複習)

給了一個prime的數組(數組中 m 個元素),返回第 n 個 ugly number,ugly number 的定義是全部的因子都必須是 prime 數組中的元素。

題解:解法同因子是 2,3,5 的醜數,咱們用 m 個指針分別指向prime數組中數應該乘的位置。而後同ugly number那題同樣。時間複雜度是 O(N*M)

 

 1 class Solution {
 2 public:
 3     int nthSuperUglyNumber(int n, vector<int>& primes) {
 4         const int m = primes.size();
 5         sort(primes.begin(), primes.end());
 6         vector<int> ptr(m, 0);
 7         vector<int> ans(n, INT_MAX);
 8         ans[0] = 1;
 9         for (int i = 1; i < n; ++i) {
10             int minn = INT_MAX;
11             for (int k = 0; k < m; ++k) {
12                 minn = min(minn, ans[ptr[k]] * primes[k]);
13             }
14             for (int k = 0; k < m; ++k) {
15                 if (minn == ans[ptr[k]] * primes[k]) {
16                     ptr[k]++;
17                 }
18             }
19             ans[i] = minn;
20         }
21         return ans[n-1];
22     }
23 };
View Code

 

【347】 Top K Frequent Elements

 

【355】 Design Twitter (2018年12月3日,heap專題)

實現四個 api。 

  1. postTweet(userId, tweetId): Compose a new tweet.
  2. getNewsFeed(userId): Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent.
  3. follow(followerId, followeeId): Follower follows a followee.
  4. unfollow(followerId, followeeId): Follower unfollows a followee.
Example:
Twitter twitter = new Twitter();

// User 1 posts a new tweet (id = 5).
twitter.postTweet(1, 5);

// User 1's news feed should return a list with 1 tweet id -> [5].
twitter.getNewsFeed(1);

// User 1 follows user 2.
twitter.follow(1, 2);

// User 2 posts a new tweet (id = 6).
twitter.postTweet(2, 6);

// User 1's news feed should return a list with 2 tweet ids -> [6, 5].
// Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5.
twitter.getNewsFeed(1);

// User 1 unfollows user 2.
twitter.unfollow(1, 2);

// User 1's news feed should return a list with 1 tweet id -> [5],
// since user 1 is no longer following user 2.
twitter.getNewsFeed(1);

題解:用個 unordered_map 標記用戶關係,而後一個 vector 存儲 twitter post

 1 class Twitter {
 2 public:
 3     /** Initialize your data structure here. */
 4     Twitter() {
 5         
 6     }
 7     
 8     /** Compose a new tweet. */
 9     void postTweet(int userId, int tweetId) {
10         twit.push_back(make_pair(userId, tweetId));
11     }
12     
13     /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
14     vector<int> getNewsFeed(int userId) {
15         set<int> people = followRelation[userId];
16         people.insert(userId);
17         vector<int> ret;
18         int idx = twit.size() - 1, cnt = 0;;
19         while (cnt < 10 && idx >= 0) {
20             auto p = twit[idx--];
21             int uid = p.first, tid = p.second;
22             if (people.find(uid) != people.end()) {
23                 ret.push_back(tid);
24                 cnt++;
25             }
26         }
27         return ret;
28     }
29     
30     /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
31     void follow(int followerId, int followeeId) {
32         followRelation[followerId].insert(followeeId);
33     }
34     
35     /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
36     void unfollow(int followerId, int followeeId) {
37         if (followRelation.find(followerId) == followRelation.end()) { return; }
38         if (followRelation[followerId].find(followeeId) == followRelation[followerId].end()) {return;}
39         followRelation[followerId].erase(followeeId);
40     }
41     
42     unordered_map<int, set<int>> followRelation;
43     vector<pair<int, int>> twit;  // (user, id)
44 };
45 
46 /**
47  * Your Twitter object will be instantiated and called as such:
48  * Twitter obj = new Twitter();
49  * obj.postTweet(userId,tweetId);
50  * vector<int> param_2 = obj.getNewsFeed(userId);
51  * obj.follow(followerId,followeeId);
52  * obj.unfollow(followerId,followeeId);
53  */
View Code

  

【358】 Rearrange String k Distance Apart

 

【373】 Find K Pairs with Smallest Sums (2018年12月1日)

給了兩個整數數組 nums1 和 nums2, 和一個整數 k,求 nums1 和 nums2 的笛卡爾積中(就是 nums1 中選擇一個數字 n1,nums2 中選擇一個數字 n2 組成pair),sum 最小的 k 個pair。

題解:本題就是自定義排序的大根堆,pair排序的規則是 sum 大的在堆頂。

 1 class Solution {
 2 public:
 3     vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
 4         if (nums1.empty() || nums2.empty()) {return vector<pair<int, int>>();}
 5         priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> pq;
 6         for (auto n1 : nums1) {
 7             for (auto n2 : nums2) {
 8                 pq.push(make_pair(n1, n2));
 9                 if (pq.size() > k) { pq.pop(); }
10             }
11         }
12         vector<pair<int, int>> ret; //可能nums1和nums2的組合的pair不夠 k 個,因此不能一開始初始化爲 k 個結果。
13         while (!pq.empty()) {
14             ret.push_back(pq.top());
15             pq.pop();
16         }
17         return ret;
18     }
19     struct cmp{
20         bool operator()(const pair<int, int>& p1, const pair<int, int>& p2) {
21             return p1.first + p1.second < p2.first + p2.second;
22         }
23     };
24 };
View Code

  

【378】 Kth Smallest Element in a Sorted Matrix

【407】 Trapping Rain Water II

【451】 Sort Characters By Frequency

 

【502】 IPO (2019年2月9日,算法羣打卡)

給了一個 n 個項目,每一個項目都有一個能力值 capital[i] 和一個利益值 profits[i],一開始有一個初始的能力值 W,要求是從這 n 個項目中選取 k 個項目,每次選取的項目的能力值capital[i]必須小於等於當前的人的能力值。每次作完一個項目,這個項目的利益值就會加在如今的能力值上面。問作完 k 個項目以後,最後能力值最大是多少。

題解:題目不難,重點在於利用heap實現。咱們想着把 capital 數組 和 profits 數組綜合成一個數組,而後給新的數組排序,排序的方式按照capital從小到大,而後 profits 隨意。

而後利用一個 heap, 每次選擇一個項目的時候,都把小於當前能力值的項目放進heap,而後從 heap 中彈出一個當前利益值最大的項目,做爲當前項目的選擇。

時間複雜度是 nlog(n)

 1 class Solution {
 2 public:
 3     int findMaximizedCapital(int k, int W, vector<int>& Profits, vector<int>& Capital) {
 4         const int n = Profits.size();
 5         vector<pair<int, int>> project(n);
 6         for (int i = 0; i < n; ++i) {
 7             project[i] = make_pair(Capital[i], Profits[i]);
 8         }
 9         sort(project.begin(), project.end());
10         priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> pq;
11         int idx = 0;
12         for (int i = 0; i < k; ++i) {
13             while (idx < n && project[idx].first <= W) {
14                 pq.push(project[idx]);
15                 ++idx;
16             }
17             if (pq.empty()) { break; }
18             pair<int, int> p = pq.top();
19             pq.pop();
20             W += p.second;
21         }
22         return W;
23     }
24     struct cmp {
25         bool operator() (const pair<int, int>& p1, const pair<int, int>& p2) const {
26             return p1.second < p2.second;
27         }  
28     };
29 };
View Code

 

【659】 Split Array into Consecutive Subsequences

 

【692】 Top K Frequent Words (2018年11月30日)

給了一個string類型的數組 words,在給定整數k,請嚴格按照出現頻率順序打印出現次數前 k 名的字符串。(出現頻率相同的按照字典順序打印)

題解:用個 unordered_map 存儲每一個單詞出現的次數,而後創建一個小根堆,裏面存 k 個pair,(小根堆自定義排序class),而後遍歷一遍map,把最後剩下在堆裏的 k 個pair的字符串提取出來。 

 1 class Solution {
 2 public:
 3     vector<string> topKFrequent(vector<string>& words, int k) {
 4         const int n = words.size();
 5         unordered_map<string, int> mp;
 6         for (auto w : words) { mp[w]++; }
 7 
 8         priority_queue<pair<string, int>, vector<pair<string, int>>, cmp> pq;  
 9         for (auto ele : mp) {
10             pq.push(ele);
11             if (pq.size() > k) { pq.pop(); }
12         }
13         vector<string> ret(k, "");
14         int idx = k-1;
15         while (!pq.empty()) {
16             auto p = pq.top();
17             pq.pop();
18             ret[idx--] = p.first;
19         }
20         return ret;
21     }
22     //自定義比較函數,爲啥我想小的排前面要寫大於。。
23     struct cmp {
24         bool operator()(const pair<string, int> a, const pair<string, int>& b) {
25             if (a.second == b.second) {
26                 return a.first < b.first;
27             }
28             return a.second > b.second;
29         }
30     };
31 };
View Code

    //自定義比較函數,爲啥我想小的排前面要寫大於。。(優先隊列的自定義比較函數要搞明白,仍是不懂啊) 

 

【703】 Kth Largest Element in a Stream

給個數字流,老是返回最大的第K個元素

解法就是用一個只有K個元素的堆,維護這這些數字裏面從最大的第K個到最大的元素。

[最小元素...第K大的元素..最大元素], 這個堆總維護後半段的K個

View Code

【719】 Find K-th Smallest Pair Distance

 

【743】 Network Delay Time (2018年12月4日)

一個社交網絡裏面有 N 個結點,標號爲 1 ~ N,給了一個 times 數組,裏面的元素 t(u, v, w) 表明從 u結點 到 v結點須要 w 的時間,給了一個源點 K, 問從 K 開始傳播一條信息,到每一個結點須要至少多少時間,若是從 K 到一個結點不可達,就返回 -1。

題解:floyed求最短路。

 1 class Solution {
 2 public:
 3     int networkDelayTime(vector<vector<int>>& times, int N, int K) {
 4         vector<vector<int>> g(N+1, vector<int>(N+1, INT_MAX));
 5         for (auto t : times) {
 6             int u = t[0], v = t[1], cost = t[2];
 7             g[u][v] = cost;
 8         }
 9         //floyed
10         for (int f = 1; f <= N; ++f) {
11             for (int i = 1; i <= N; ++i) {
12                 g[i][i] = 0;
13                 for (int j = 1; j <= N; ++j) {
14                     if (g[i][f] != INT_MAX && g[f][j] != INT_MAX) {
15                         g[i][j] = min(g[i][f] + g[f][j], g[i][j]);
16                     }
17                 }
18             }
19         }
20         int ret = INT_MIN;
21         for (int i = 1; i <= N; ++i) {
22             if (i == K) {continue;}
23             if (g[K][i] == INT_MAX) {
24                 ret = -1;
25                 break;
26             }
27             ret = max(ret, g[K][i]);
28         }             
29         return ret;            
30     }
31 };
View Code

此外,我沒看出來跟 heap 有啥關係。

 

【759】 Employee Free Time

【767】 Reorganize String

【778】 Swim in Rising Water

【786】 K-th Smallest Prime Fraction

 

【787】 Cheapest Flights Within K Stops (2019年2月9日)

2019年4月6日更新。heap 是個好東西。

給定了一張有向圖,還有邊的權重,問最多通過K個結點的狀況下,從 src 到 dst 的最小花費。

題解:能夠用 dijkstra 的思路,只不過這個題多了一個條件是最多通過 K 個結點,那麼咱們就能夠在放入heap的結點中,新增一個緯度,叫作通過的站數。

 

 1 //dijkstra 的思路,加上一個K站的條件
 2 class Solution {
 3 public:
 4     int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
 5         vector<vector<int>> graph(n, vector<int>(n, -1));
 6         for (int u = 0; u < n; ++u) { graph[u][u] = 0; }
 7         for (auto& f : flights) {
 8             int u = f[0], v = f[1], w = f[2];
 9             graph[u][v] = w;
10         }
11         priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq; //{cost, city, how many stops visited}
12         pq.push({0, src, 0});
13         while (!pq.empty()) {
14             auto temp = pq.top(); pq.pop();
15             int price = temp[0], city = temp[1], stops = temp[2]; 
16             if (city == dst) {return price;}
17             for (int v = 0; v < n; ++v) {
18                 if (graph[city][v] == -1 || city == v) {continue;}
19                 if (stops <= K) {
20                     pq.push({price + graph[city][v], v, stops + 1});
21                 }
22             }
23         }
24         return -1;
25     }
26 };
View Code

 

 

 

【818】 Race Car

 

【857】 Minimum Cost to Hire K Workers (2019年3月15日,google tag)

題目給了兩個規則讓咱們設計一個花費最小的辦法僱傭K個工人。

  1. Every worker in the paid group should be paid in the ratio of their quality compared to other workers in the paid group. 必須按照unitWage最大的那個工人的unitWage來付全部人的錢。
  2. Every worker in the paid group must be paid at least their minimum wage expectation.

題解:咱們考慮若是將wage[i]/quality[i]做爲評價指標來進行排序意味着什麼?unitWage從小到大排序。 (wisdompeak大佬的題解)

wage[i]/quality[i]最高的那位,意味着最不實惠的工人,它拉高了unitWage,使得其餘工人都必須按照這個unitWage乘以各自的quality拿工資.但轉念一想,若是咱們必須僱傭這個最不實惠的工人的話,那麼剩下的工人該如何選擇呢?顯然咱們只要選K-1個quality最低的工人,他們能夠拉高那個"最不實惠工人"的quality比重,從而減小其餘工人的quality比重,從而下降總工資.

咱們再考慮,若是選擇了wage[i]/quality[i]第二高的那位,那麼咱們就在接下來的 N-2 我的裏面選擇 K-1 個quality最底的工人便可.

由此貪心法的最優策略就出來了.實際操做中,咱們根據 wage[i]/quality[i] 從低到高進行處理.

 1 class Solution {
 2 public:
 3     double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) {
 4         int n = quality.size();
 5         vector<pair<double, int>> workers(n);
 6         for (int i = 0; i < n; ++i) {
 7             workers[i] = {(double)wage[i]/quality[i], quality[i]};
 8         }
 9         sort(workers.begin(), workers.end());
10         int totQuality = 0;
11         double res = DBL_MAX;
12         priority_queue<int, vector<int>, less<int>> pq;
13         for (int i = 0; i < n; ++i) {
14             double unitWage = workers[i].first;
15             int qua = workers[i].second;
16             if (pq.size() == K) {
17                 totQuality -= pq.top();
18                 pq.pop();
19             }
20             totQuality += qua;
21             pq.push(qua);
22             if (pq.size() == K) {
23                 res = min(res, unitWage * totQuality);
24             }
25         }
26         return res;
27     }
28 };
View Code

 

【864】 Shortest Path to Get All Keys

【871】 Minimum Number of Refueling Stops

【882】 Reachable Nodes In Subdivided Graph

相關文章
相關標籤/搜索