如何优化42学校Push_swap算法以减少排序指令数?
Push_swap 算法优化方案
核心算法替换:放弃逐个移最小元素,改用分块贪心(Turk算法)
你的基础算法每次单独移动最小元素,本质是O(n²)的时间复杂度,大数据量下指令数必然爆炸。Turk算法是Push_swap项目中最常用的高效方案,核心思路是分块批量处理,大幅降低操作次数:
- 分块策略:根据数据量划分数值区间,比如n=100分5块(每块20个连续索引值),n=500分10块(每块50个)。先把栈A中的元素按块批量移到栈B。
- 栈B维护:移动过程中,在栈B内保持块元素的相对有序(比如让当前块的较大元素尽量靠近栈顶,或者让下一个要处理的块元素处于易移动位置),避免后续移回时的大量调整操作。
- 批量移回:当所有元素都移到栈B后,按从大到小的顺序将元素移回栈A——此时栈B中最大元素要么在栈顶,要么只需要少量旋转就能到栈顶,每次
pa即可,操作数会大幅减少。
分治思路(类快速排序)
另一种可选方案是借鉴快速排序的分治逻辑,通过基准值拆分栈:
- 选一个基准值(比如栈A的中位数),将小于基准的元素移到栈B,大于等于的留在栈A。
- 递归处理栈A(继续拆分排序),再递归处理栈B,最后将栈B的元素按顺序移回栈A。
- 这种方案的指令数也能轻松达标,且逻辑相对容易实现。
操作指令层面的优化
不管用哪种核心算法,以下优化都能进一步压缩指令数:
- 合并并行操作:当需要同时旋转栈A和栈B时,用
rr替代ra+rb;同时反向旋转时用rrr替代rra+rrb,直接减少一半指令。 - 最优路径计算:计算元素到栈顶的顺时针(
ra/rb)和逆时针(rra/rrb)步数,选步数更少的方向移动,避免无效操作。 - 预处理数值映射:将原始乱序数值转换成0到n-1的连续索引(比如把[5,2,9]转换成[1,0,2]),这样更容易判断元素所属块、大小关系,减少遍历比较的开销。
细节调优
- 小数据硬编码:对于n≤5的情况,直接写死最优指令序列(比如n=3最多用3条指令),不用走复杂算法,节省操作。
- 维护栈状态缓存:提前记录栈A/B的最小值、最大值、元素位置映射表,不用每次遍历找元素,减少计算时间的同时也能更快确定移动策略。
按照上述方案优化后,n=100的指令数可以控制在400以内,n=500能稳定在4500左右,完全满足项目要求。
内容的提问来源于stack exchange,提问作者Emperor_Udan
相关产品推荐
相关产品推荐

