LeetCode406 queue-reconstruction-by-height详解
题目详情
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。
注意:
总人数少于1100人。
示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
解题思路
此题放在贪心算法中, 是用贪心的思想来解题
首先对数组 按照第一个元素height 降序排列
此时 数组前面的元素的height 大于后面元素的height
然后 以每个元素的k值 插入到返回数组里, 比如元素的k为 2, 就插到 返回数组的下标为2的位置。
以题目的例子来进行操作
这是原来的数组
people = [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
按照height进行降序排序之后
people = [[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
对降序后的people数组 从第一个元素开始 把每个元素加入到返回数组
加入的策略是, 按照每个元素的k 来插入到下表为k的位置上
1.
插入 [7,0]
插入到离开始位置偏移了0个距离的位置。
result = [[7,0]]
2.
插入 [7,1]
插入到离开始位置偏移了1个距离的位置,即插入到[7,0]的后面。
result = [[7,0], [7,1]]
3.
插入 [6,1]
插入到离开始位置偏移了1个距离的位置,即插入到[7,0]的后面。
result = [[7,0], [6,1], [7,1]]
4.
插入 [5,0]
插入到离开始位置偏移了0个距离的位置,即插入到[7,0]的前面。
result = [[5,0], [7,0], [6,1], [7,1]]
5.
插入 [5,2]
插入到离开始位置偏移了2个距离的位置,即插入到[7,0]的后面。
result = [[5,0], [7,0], [5,2], [6,1], [7,1]]
6.
插入 [4,4]
插入到离开始位置偏移了4个距离的位置,即插入到[6,1]的后面。
result = [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
得到最终结果
result: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
贪心证明
把每个元素以k 插进去, 因为是按照height 来由大到小插进去的, 把元素插进第k位置, 插入后前面的height 是比当前插入元素大(因为已经插入的元素height大或者相等), 这就满足了排在前面身高大于或等于的人数为k, 但是要注意 我现在说的数组 并不是最终结果的数组, 而是插入这个元素形成的中间数组。 是相对于 中间数组来说的。
那么有一个问题了, 最终结果里 [6,1] 前面有[5,0], [5,1], 这些height是小于6的, 但是排在[6,1]前面, 这些元素是在[6,1]加进去之后加进去的, 这些加进去的元素对 [6,1] 满足的条件(排在前面身高大于或等于的人数为k) 会有影响吗? 答案是不会的,因为在[6,1]加进去的元素的height 是小于6的 无论加在哪个地方对 [6,1]的 k 不会改变。
综上, 此算法能求出结果
AC代码
class Solution {
public:
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
vector<pair<int, int>> result;
// lambda 表达式
sort(people.begin(), people.end(), [](pair<int, int> a, pair<int, int> b){
return a.first > b.first || (a.first == b.first && a.second < b.second);
});
for (auto i: people) {
result.insert(result.begin() + i.second, i);
}
return result;
}
};
总结
因为在前面贪心的过程中 插入的元素不会对前面已经插入元素的k造成印象, 所以才能贪心, 否则 就可能用到其他的方法来解题了。