Medium
题目描述
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
示例 1:
输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0,1,2,3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。
示例 2:
输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
提示:
1 <= people.length <= 20000 <= hi <= 10^60 <= ki < people.length- 题目数据确保队列可以被重建
解题思路
解题思路
这是一个经典的贪心算法题目,关键在于找到正确的排序和插入策略。
核心观察
- 从高到低的贪心策略:对于身高较高的人,他们的相对位置更容易确定,因为只有身高大于等于他们的人才会影响他们的 k 值。
- 插入位置的确定:当我们按身高从高到低处理时,对于当前人员
[h, k],他应该插入到结果数组的第 k 个位置(0-based)。
算法步骤
- 排序:按身高降序排列,身高相同时按 k 值升序排列
- 插入:遍历排序后的数组,将每个人插入到结果数组的第 k 个位置
为什么这样有效?
- 当我们处理身高为 h 的人时,已经插入的都是身高 ≥ h 的人
- 这些已插入的人正好是会影响当前人 k 值的人
- 因此直接在第 k 个位置插入即可
推荐解法:贪心算法 + 插入排序,时间复杂度虽然是 O(n²),但思路清晰且易于理解。
代码实现
class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
// 按身高降序,身高相同时按k值升序排序
sort(people.begin(), people.end(), [](const vector<int>& a, const vector<int>& b) {
if (a[0] == b[0]) {
return a[1] < b[1];
}
return a[0] > b[0];
});
vector<vector<int>> result;
// 按排序后的顺序,将每个人插入到第k个位置
for (const auto& person : people) {
result.insert(result.begin() + person[1], person);
}
return result;
}
};
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
# 按身高降序,身高相同时按k值升序排序
people.sort(key=lambda x: (-x[0], x[1]))
result = []
# 按排序后的顺序,将每个人插入到第k个位置
for person in people:
result.insert(person[1], person)
return result
public class Solution {
public int[][] ReconstructQueue(int[][] people) {
// 按身高降序,身高相同时按k值升序排序
Array.Sort(people, (a, b) => {
if (a[0] == b[0]) {
return a[1].CompareTo(b[1]);
}
return b[0].CompareTo(a[0]);
});
var result = new List<int[]>();
// 按排序后的顺序,将每个人插入到第k个位置
foreach (var person in people) {
result.Insert(person[1], person);
}
return result.ToArray();
}
}
/**
* @param {number[][]} people
* @return {number[][]}
*/
var reconstructQueue = function(people) {
people.sort((a, b) => {
if (a[0] !== b[0]) {
return b[0] - a[0];
}
return a[1] - b[1];
});
const result = [];
for (const person of people) {
result.splice(person[1], 0, person);
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n²) | 排序需要 O(n log n),插入操作最坏情况下需要 O(n²) |
| 空间复杂度 | O(n) | 需要额外的结果数组存储重建后的队列 |
相关题目
. Reward Top K Students (Medium)