题目描述
思路解析动画文字版
笨办法:把所有人排成 n 的阶乘种顺序,逐个检查每个人前面的高个数是否等于 k。n 一到 2000,排列数直接爆炸,根本跑不动。
转折点:先按身高从高到低排,同身高的按 k 从小到大排。这样每次要插的人,都比队列里已有的人矮或一样高,于是直接把他插到下标 k,前面就刚好有 k 个不比他矮的人。
为什么后插的矮个不会破坏前面高个的 k?因为高个只数「不比自己矮的人」,而后插进来的矮个比他矮,根本不会被高个数进去。插矮个对高个的 k 是「隐形」的。
第 1 步:排序,高个在前,同高 k 小在前:排完序:7、7、6、5、5、4 身高从高到低。注意主舞台这个空队列就是答案 ans,待插入的人在右侧面板里排好队,一个个往里塞。
插入 [7,0]:k=0,放到下标 0:最高的 7 先进场。它的 k=0,要求前面没人不比它矮,所以放到队首下标 0。
插入 [7,1]:k=1,放到下标 1:第二个 7,k=1,插到下标 1。它前面正好站着一个 [7,0],身高 7 不比它矮,k 满足。
插入 [6,1]:插到下标 1,后面整体右移:6 比队列里的两个 7 都矮。它 k=1,插到下标 1:原来站这儿的 [7,1] 被往右挤一格。看下标 2 的 [7,1] 是怎么被顶过去的。
灵魂帧 · 慢放「插入即右移」:把这一步删掉文字也要看懂:[6,1] 占了下标 1,[7,1] 从 1 退到 2。[7,1] 前面新增的是更矮的 [6,1],6 不比 7 矮的人不增加,所以 [7,1] 的 k=1 依然成立。这就是「矮个对高个隐形」的现场。
插入 [5,0]:k=0,插到队首,全体右移:5 比前面所有人都矮,k=0,插到队首。后面三个人全体右移一格,但他们前面新增的是更矮的 5,k 全都不受影响。
插入 [5,2]:k=2,放到下标 2:第二个 5,k=2,插到下标 2。它前面是 [5,0] 和 [7,0],身高都至少 5,正好 2 个,条件满足。
插入 [4,4]:k=4,放到下标 4:最矮的 4 最后进场,k=4,插到下标 4。它前面四个人身高都不比 4 矮,全部满足,队列拼完。
抽查 [6,1]:它的 k 真的对吗?:随手抽查 [6,1]。它前面三个人里,只有 [7,0] 身高不比 6 矮,另外两个 5 都比 6 矮不算。正好 1 个,k=1 成立。算法对了。
返回最终队列:最终队列不一定按身高有序,但每个人的 k 条件全都对。注意:答案可能不唯一,但本题保证至少有一个合法答案。
一句话本质:当一个约束只跟「比自己更高的人」有关,就先把高个排定,后来的矮个对高个完全隐形,于是 k 直接当插入下标。
雷区实演:同高 k 排反,最终在 [5,2] 翻车:用本课代码真跑「同高 k 降序」:前几步并不会当场崩,错误是悄悄累积的——同高的两人里 k 大的先插,随后被 k 小的插入挤动,相对次序就乱了。最终在更矮的 [5,2] 处暴露:它前面挤进了 [5,0]、[7,0]、[6,1] 三个不矮于 5 的人,而 k 只要 2,对不上。错误队列 [[5,0],[7,0],[6,1],[5,2],[4,4],[7,1]] 中标红的 [5,2] 就是崩点。这才是「同高必须 k 升序」的真实理由。
面试追问:面试时把动画里的「排序方向 + 下标 k 的等价性 + 复杂度瓶颈」讲成自己的话,这题就稳了。
这题的内核是「先按一个维度排定,让后续操作对它无害」。同一招还能解:LC135 分发糖果(左右各扫一遍)、LC435 无重叠区间(按右端点排序贪心)、LC452 用最少箭引爆气球。学会「排哪个维度能让后续不破坏前面」,这一类贪心就通了——更多在 贪心专题 继续,卡住时让小欧私教陪你把这套骨架套到下一题。
边界三连:边界先看:同身高怎么排、k=0 落哪、只有一个人时会不会出错。这三种最容易暴露排序方向写反的 bug。
参考代码
class Solution: def reconstructQueue(self, people): # 身高降序;同高时 k 升序 people.sort(key=lambda p: (-p[0], p[1])) ans = [] for p in people: ans.insert(p[1], p) # k 当下标插入 return ans复杂度
- 时间复杂度:O(n²),排序 O(n log n);但 list 在中间 insert 一次最坏要移动 O(n) 个元素,n 次插入合计 O(n²),这才是主项。
- 空间复杂度:O(n),ans 存重建后的整支队列;排序若原地则只占常数额外空间。
可套用的代码模板
这是挖空骨架,不是抄答案。三个空对应贪心排序题的三连问:① 先排哪个维度能让后续不破坏前面?② 用什么结构累积答案?③ 当前元素的落点/决策怎么由它自己算出?本题答案:① 身高降序+k 升序 ② 列表 ③ pos=k。换题只改这三处。
# 贪心排序通法:定排序维度 → 顺序处理 → 维护一个结构items.sort(key=lambda x: (____, ____)) # ① 关键:先排哪个维度result = [] # ② 累积答案的结构for x in items: pos = ____ # ③ 由当前元素算出落点/决策 result.insert(pos, x) # 本题:pos = x 的 kreturn result易错点
面试追问把动画讲成自己的话
追问排序规则为什么是「身高降序、同高 k 升序」?反过来排会怎样?
追问为什么 insert 的下标可以直接用 k,不用真的去数前面有几个高个?
追问复杂度瓶颈在哪?能不能优化掉 O(n²)?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。再去主线里挑下一道练手。
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题