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

第一次接触贪心算法的题目,主要是如何进行贪心选择。这里需要注意的是当身高相同的时候需要选择:排在前面人少的那一位优先推入结果队列,这样才能保证它排在相同身高的人前面。

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