最近算法課講到了貪心算法,接下來的幾篇題解應該都會與貪心算法相關。
1. 題目描述
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.
Note: The number of people is less than 1,100.
2. 樣例
Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
3. 分析
3.1. 題目分析
首先分析一下題目要求:給了一系列pair對,每一個pair代表目前一個隊列裏面的一個人。pair的第一個元素代表該人的身高,第二個元素代表站在該人前面,並且身高大於等於該人的其他人的數目。
例如:[4, 4]代表這個人身高爲4,他前面總共有4個人的身高大於等於4。
需要我們做的事情是:按照input的隊列情況,將整個隊列重新排列,以求他們都能夠站到對應的位置上面。
3.2. 貪心算法
書本和網上已經有很多關於貪心算法的講解,這裏筆者就不再贅述了,只是談幾點自己對於貪心的理解:
- 貪心算法實際上是局部最優解,即它每一步的行爲都是求解當前情況下,最好的解決方案;
- 由於是局部最優解,可能最終的解法不一定是最優的;
- 算法的解題思想是:將問題劃分爲若干子步驟,選擇好每一個子步驟的解題思想,朝向最貪心的方向努力;
之前看到了一個非常好的例子,筆者覺得非常形象,貼在這裏和大家分享一下:
【例子】
有一個揹包,揹包容量是M=150。有7個物品,物品可以分割成任意大小。要求儘可能讓裝入揹包中的物品總價值最大,但不能超過總容量。
我們可以有如下三種策略:
- 根據貪心的策略,每次挑選價值最大的物品裝入揹包,得到的結果是否最優?
- 每次挑選所佔重量最小的物品裝入是否能得到最優解?
- 每次選取單位重量價值最大的物品,成爲解本題的策略。
我們驗證之後,發現並非第一個方案就是最合適的。
3.3. 解題思路
我們將問題列爲貪心算法:我們可以這樣設計,每一次都從隊列裏面找到當前最高的人,將其放入結果的vector裏面,然後在接下來剩餘的人裏面繼續找當前最高的人,將其根據排在前面的人的數量插入到結果隊列裏面合適的位置。
【例子】
Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
Sorted:
[[4,4], [5,2], [5,0], [6,1], [7,1], [7,0]]
1st:
[[7,0]]
2nd:
[[7,0], [7,1]]
3rd:
[[7,0], [6,1], [7,1]]
4th:
[[5,0], [7,0], [6,1], [7,1]]
5th:
[[5,0], [7,0], [5,2], [6,1], [7,1]]
6th:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
排序首先是按照:每個人的身高升序排列,然後在相同身高情況下按照排在前面人數降序排序,經過排序後,我們就可以得到隊列裏面人的身高排列情況。
接着從排好序的隊列裏面找出當前最高的人,即排在隊列最後的人,插入結果隊列。因此已經是排好序的了,所以之後每次按照排在前面人的數目進行插入。
4. 源碼
class Solution {
public:
static bool Comp(pair<int, int>a, pair<int, int>b) {
if (a.first < b.first) {
return true;
}
else if (a.first == b.first) {
if (a.second > b.second) {
return true;
}
}
return false;
}
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
vector<pair<int, int> > result;
sort(people.begin(), people.end(), Comp);
while(!people.empty()) {
pair<int, int>temp = people.back();
people.pop_back();
result.insert(result.begin() + temp.second, temp);
}
return result;
}
};
5. 心得
第一次接觸貪心算法的題目,主要是如何進行貪心選擇。這裏需要注意的是當身高相同的時候需要選擇:排在前面人少的那一位優先推入結果隊列,這樣才能保證它排在相同身高的人前面。