煎饼排序:翻转序列
Pancake Sort: Flip Sequence
开始编码你在为某行情归档系统写报价磁带的诊断排序例程。硬件是一种受限的「煎饼铲」式缓冲区——能做的唯一操作是前缀反转:给定一个数组,你可以反转前 k 个元素(任意 1 ≤ k ≤ N)。目标是用一系列前缀反转把数组排成升序,并**输出你用过的 k 序列**。这就是经典的*煎饼排序*问题(LeetCode 969),是面试与微观结构代码中常见的排列排序练习——后者尤其出现在「重排队头/倒带」是唯一原语的场景里。
请实现 solution(arr: list[int]) -> list[int]。输入是互异整数的排列,返回一个 flip 大小列表,使得依次对输入数组施加 flip(k)(原地反转 arr[0:k])后得到升序数组。不要求最优——任何长度 ≤ 2·N 的合法序列都被接受——但验题器会逐项精确对比你的输出与参考答案,所以你必须使用规范的贪心 + 确定性 tie-break:在缩小的前缀大小 s = N, N-1, …, 2 上循环,找到 arr[0:s] 中最大值的最左下标,flip(idx+1) 把它翻到最前(已在位置 0 则跳过),再 flip(s) 把它送到位置 s-1(最大值已在位置 s-1 则整轮跳过)。边界情况:已排序输入返回 [];[2, 1] 返回 [2];单元素输入返回 []。
示例 1:solution([3, 2, 4, 1]) 返回 [3, 4, 2, 3, 2]。过程:s=4 轮,最大值 4 在位置 2,flip 3 得 [4, 2, 3, 1],flip 4 得 [1, 3, 2, 4]。s=3 轮,最大值 3 在位置 1,flip 2 得 [3, 1, 2, 4],flip 3 得 [2, 1, 3, 4]。s=2 轮,最大值 2 已在位置 0(跳过 bring-to-front),flip 2 得 [1, 2, 3, 4]。共 5 次 flip,远低于 2·N = 8 上限。
示例 2:solution([5, 4, 3, 2, 1]) 返回 [5]。完全逆序是最简单的情形:一次长度为 5 的前缀反转直接得到 [1, 2, 3, 4, 5]。示例 3:solution([1, 2, 3, 4, 5]) 返回 []——已排序,贪心循环不产生任何 flip。
关于「**为什么是 O(N) 次 flip 而不是 O(N log N)**」:煎饼排序的主要成本不在 flip 本身而在每轮 find-max 的扫描,总时间是 O(N²);但 *flip 次数*被 2(N-1) 严格界住,因为每轮永久放好一个元素。在那些「重排本身昂贵」的领域——例如只能旋转订单簿队头或回退一段磁带缓冲——重要的是 flip 计数而非比较计数。这里的贪心是教科书上界;找最少 flip 数其实是 NP-hard 的,所以面试题问的是 ≤ 2·N,不是最优。
约束条件
- 1 ≤ len(arr) ≤ 100
- arr 是一个互异整数排列(无重复)
- 输出的每个 flip k 满足 1 ≤ k ≤ len(arr);按顺序对输入数组应用这些 flip 必须得到 sorted(arr) 升序结果
- 输出不要求最短,但必须 ≤ 2·N 次 flip
- Tie-break:每轮取未排序前缀中最大值的最左下标;只有当最大值不在位置 0 时才输出 bring-to-front 翻转;最大值已在尾部位置时整轮跳过
样例
Case 1 · LC969 classic [3,2,4,1]
输入: [[3,2,4,1]]
期望: [3,4,2,3,2]
标准 LeetCode 969 用例。第 1 轮 s=4:a[0:4] 中最大值 4 在位置 2,先 flip 3 把 4 翻到最前 → [4,2,3,1],再 flip 4 把 4 送到末尾 → [1,3,2,4]。第 2 轮 s=3:最大值 3 在位置 1,先 flip 2 → [3,1,2,4],再 flip 3 → [2,1,3,4]。第 3 轮 s=2:最大值 2 在位置 0,已在前端故省一次 flip,直接 flip 2 → [1,2,3,4]。共 5 次 flip,未超过 2N=8。
Case 2 · already sorted — no flips needed
输入: [[1,2,3,4,5]]
期望: []
已经升序,每一轮中最大值都在对应的尾部位置,贪心算法直接 continue 不产生 flip。返回空列表,验证「无操作」是合法答案。
Case 3 · fully reversed — single big flip
输入: [[5,4,3,2,1]]
期望: [5]
一次反转就能搞定:翻转前 5 个就把整个数组变成升序。第一轮把最大值 5 送到末尾后,剩下的 [4,3,2,1] 在递归回看时其实也已经是降序——但贪心算法只关心当前最大值的位置,每轮 max 都恰好在前端,所以只产生 1 次 flip。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · LC969 classic [3,2,4,1]
输入: [[3,2,4,1]]
期望: [3,4,2,3,2]
标准 LeetCode 969 用例。第 1 轮 s=4:a[0:4] 中最大值 4 在位置 2,先 flip 3 把 4 翻到最前 → [4,2,3,1],再 flip 4 把 4 送到末尾 → [1,3,2,4]。第 2 轮 s=3:最大值 3 在位置 1,先 flip 2 → [3,1,2,4],再 flip 3 → [2,1,3,4]。第 3 轮 s=2:最大值 2 在位置 0,已在前端故省一次 flip,直接 flip 2 → [1,2,3,4]。共 5 次 flip,未超过 2N=8。
Case 2 · already sorted — no flips needed
输入: [[1,2,3,4,5]]
期望: []
已经升序,每一轮中最大值都在对应的尾部位置,贪心算法直接 continue 不产生 flip。返回空列表,验证「无操作」是合法答案。
Case 3 · fully reversed — single big flip
输入: [[5,4,3,2,1]]
期望: [5]
一次反转就能搞定:翻转前 5 个就把整个数组变成升序。第一轮把最大值 5 送到末尾后,剩下的 [4,3,2,1] 在递归回看时其实也已经是降序——但贪心算法只关心当前最大值的位置,每轮 max 都恰好在前端,所以只产生 1 次 flip。