LeetCode406. Queue Reconstruction by Height題解

最近算法課講到了貪心算法,接下來的幾篇題解應該都會與貪心算法相關。

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. 心得

第一次接觸貪心算法的題目,主要是如何進行貪心選擇。這裏需要注意的是當身高相同的時候需要選擇:排在前面人少的那一位優先推入結果隊列,這樣才能保證它排在相同身高的人前面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章