LeetCode 406. 根据身高重建队列
题目描述


题意分析
每个人用
[h, k]表示:身高为h,最终队列中排在他前面、且身高不低于h的人数恰好为k。根据打乱的这些记录,恢复一条满足所有人条件的队列。
k不是最终下标,也不统计前面的矮个子;与自己同高的人要计入。题目保证能够重建,输出保留每个人的完整记录,只调整排列顺序。
解法:身高降序排序后按 k 插入
核心思路
[!blue]
难点是一个人的有效前驱取决于身高。先按身高从高到低处理,就能让当前已放入列表的人全部不矮于新人,列表中的每个人都计入新人的
k,于是它可以直接作为插入下标。把新人插到下标
k,其前面正好有k个已有元素,因此他的条件立即满足。这里是插入而非覆盖,原来从该位置开始的人需要整体向后移动,所有记录仍各保留一份。还要保证后续操作不会破坏已经放好的人。之后加入的严格矮者,即使插到高者前面,也不计入高者的有效前驱,所以无影响;同身高的人则必须按
k从小到大处理,较大k的后来者插在已放同高者之后,不会增加他们前面的同高人数。两条排序规则因此缺一不可:身高降序使已有列表中的所有人都能为当前人计数,同高
k升序使后来的同高者不会破坏已经满足的约束。有解的前提也保证每次所需的插入下标都在当前列表允许范围内。Java 用列表按下标插入;Go 先把切片长度加一,再用支持重叠区间的
copy将后缀右移,最后写入空出的下标。实现会排序输入数组,然后构造结果队列。
解题步骤
- 将记录按身高降序排序,同身高按
k升序排序。- 从空结果列表开始,依次读取排序后的人。
- 在结果下标
person[1]处插入当前记录,原后缀整体右移。- 所有人插入完成后返回结果队列。
代码实现
class Solution {
// 对身高降序排序,同身高按 k 升序排序,可以保证插入当前人时,结果中已有的人都不矮于他。
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(
people,
(first, second) -> {
if (first[0] != second[0]) {
return Integer.compare(second[0], first[0]);
}
return Integer.compare(first[1], second[1]);
});
List<int[]> res = new ArrayList<>();
for (int[] person : people) {
// 已有者都不矮于当前人,插入后前面恰有指定人数
res.add(person[1], person);
}
return res.toArray(new int[people.length][2]);
}
}
import "sort"
func reconstructQueue(people [][]int) [][]int {
// 对身高降序排序,同身高按 k 升序排序,可以保证插入当前人时,结果中已有的人都不矮于他。
sort.Slice(people, func(i, j int) bool {
if people[i][0] != people[j][0] {
return people[i][0] > people[j][0]
}
return people[i][1] < people[j][1]
})
res := make([][]int, 0, len(people))
for _, person := range people {
idx := person[1]
// 已有者都不矮于当前人,插入后前面恰有指定人数
res = append(res, nil)
// 先扩展长度,再用支持重叠的复制向右移位
copy(res[idx+1:], res[idx:])
res[idx] = person
}
return res
}
复杂度分析
- 时间复杂度:$O(n^2)$,按下标插入的移位主导。
- 空间复杂度:$O(n)$,结果与排序辅助空间。
关键点总结
[!green]
- 原始的
k不是最终下标,只有按身高顺序构造的当前列表里,才等价于插入下标。- 严格矮者不影响高者,同高者会相互计数,需要额外按
k升序控制。- 插入保留所有已有元素,不能用覆盖赋值代替。
- Go 必须先扩长再右移,
copy能正确处理重叠源区间与目标区间。
易错点总结
[!yellow]
- 同身高按
k降序处理,可能过早使用当前列表尚不存在的插入位置,也会破坏同高约束。- 按身高升序后仍直接以
k插入,已有矮者不能全部计入有效前驱。- 直接覆盖结果下标会丢掉原来的人员记录,应执行真正的插入。
person[0]是身高,person[1]才是所需人数,不能混作插入位置。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 1389. 按既定顺序创建目标数组 | 简单 | 同样根据插入位置构造序列,本题先按身高降序,使k恰好成为当前队列的插入下标。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!