题目描述
思路解析动画文字版
为什么不像选择排序那样扫全局?因为左边已经有序了,新牌只要和左边从右往左挨个比,遇到第一个不比它大的就停——逆序时最慢要比到头(O(n²)),但近乎有序时几乎一比就停(O(n))。
每插入完第 i 个数,前缀 0..i 一定有序。插入靠的是"把左边比它大的整体右移一格腾出空位",而不是交换——右移比交换省一次赋值,还保持稳定。
5 是已排序起点:先把第一个数 5 看作已排序区(绿色)。从下标 1 的 2 开始往左插。
插 2 · 比 5 小 → 5 右移:取出 cur=2 暂存(下标 1 这格视作空位)。和左边 5 比:5 大于 2,把 5 右移一格盖到下标 1,继续往左。
插 2 · 左边到头 → 落位:j 已经越过最左端(j=-1),没有更多牌可比,把 cur=2 放进下标 0。前缀变成 [2,5] 有序。
插 4 · 比 5 小 → 5 右移:取出 cur=4。和左边 5 比:5 大于 4,5 右移到下标 2,j 退到下标 1。
插 4 · 遇到 2 不大 → 停:再和 2 比:2 不大于 4,循环停下——这就是关键负例分支,内层不再右移。把 cur=4 落到 2 右边那个空位。前缀 [2,4,5]。
插 1 · 比 5 小 → 5 右移:取出 cur=1。它比左边 5 小,5 右移到下标 3。
插 1 · 4 也大 → 再右移:继续往左:4 也大于 1,4 右移到下标 2。可见逆序时要连着右移好几格,这正是插入排序最坏 O(n²) 的来源。
插 1 · 2 也大 → 移到最前:2 也大于 1,再右移;j 越过最左端,cur=1 落到下标 0。前缀 [1,2,4,5]。
插 3 · 5、4 右移,遇 2 停:取出 cur=3:5 右移、4 右移,比到 2 时 2 不大于 3,停下,3 落进 2 和 4 之间。整个数组 [1,2,3,4,5] 有序。
插入排序"自适应"——越接近有序越快,这是它相比选择排序的独特优势(选择排序无论如何都跑满 n²/2)。很多库的排序在小区间正是用它收尾。
参考代码
for i in range(1, len(nums)): cur = nums[i] # 取出待插入的牌,腾出空位 j = i - 1 # 从前缀最右开始往左找 while j >= 0 and nums[j] > cur: # 比 cur 大的整体右移 nums[j + 1] = nums[j] # 右移一格(不是交换) j -= 1 nums[j + 1] = cur # 遇到不比它大的,落位复杂度
- 时间复杂度:O(n²),最坏(完全逆序)每个数都要移到头;近乎有序时退化到 O(n)
- 空间复杂度:O(1),只在原数组上右移,不开额外数组
可套用的代码模板
记住骨架:取当前数、左边大的右移、腾出位置落下。希尔排序就是"分组的插入排序",把速度提到亚平方级。
Python
for i in range(1, n): cur, j = a[i], i - 1 while j >= 0 and a[j] > cur: # 大的右移腾位 a[j + 1] = a[j]; j -= 1 a[j + 1] = cur # 落位易错点
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
最大数
LeetCode 179 · 中等 · 沿着 排序套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题