当前位置: 首页 > news >正文

C语言学习笔记20260705-基于栈的排列重排——求字典序最大的合法出栈序列

C语言学习笔记20260705-基于栈的排列重排——求字典序最大的合法出栈序列

1. 题目概述

给定一个从 1到 n 的排列 P,以及一个空栈。我们需要按顺序将排列中的元素依次入栈,并可以在任意时刻选择将栈顶元素出栈并将其加入输出序列(入栈顺序不可改变)。

理想情况下,我们希望得到一个严格从大到小排序的输出序列。但受栈操作限制,可能无法完全实现。当无法完全排序时,请输出字典序最大的合法出栈序列。

输入描述
第一行输入一个整数 n
第二行输入n 个整数,表示排列P中的元素,用空格分隔。保证给出的是一个从 1 到 n的排列。

输出描述
输出一行,包含若干整数,表示最终的出栈序列,用空格分隔,结尾不输出多余空格。


2. 核心难点与贪心策略

入栈顺序不可改变,但出栈时机可以自由决定。本题的核心难点在于:什么时候该弹出栈顶元素?

要想让输出序列的字典序最大,贪心的思想是“尽可能让大的数字靠前”。如果当前栈顶元素为 x,而后续未入栈的元素中存在比 x 更大的数字 y,那么 y 入栈后出栈,得到的字典序一定比现在更大就把 x弹出来。

因此,贪心策略的核心判断条件是:
只有当栈顶元素大于或等于后续所有未入栈元素的最大值时,才将其弹出。如果后续还有更大的数等待入栈,当前栈顶就必须暂时留在栈中,以免阻塞更大元素的输出。


3. 算法思路:后缀最大值 + 模拟栈

为了在 O(1)时间内判断“后续是否还有更大的数”,我们需要提前预处理出后缀最大值。整个算法分为三步:

第一步:预处理后缀最大值

定义数组suf_max[i],表示从位置 i 到数组末尾中,所有元素的最大值。通过从后往前遍历一次即可求出:
suf_max[i] = max(P[i], suf_max[i+1])
这样,当我们处理到第 i个元素时,suf_max[i+1]就代表了“后面所有未入栈元素的最大值”。

第二步:逐个入栈,贪心弹出

遍历排列 P,将元素依次压入栈中。每次压入后,检查栈顶元素与后缀最大值的关系:

  • 栈顶元素 >= suf_max[下一个未入栈位置],说明后面没有比它更大的数了,安全弹出并输出。
  • 循环检查,直到栈为空或栈顶元素小于后缀最大值。

第三步:清空栈中剩余元素

当所有元素都入栈并处理完毕后,栈中剩余的元素只能按照“先进后出”的顺序依次弹出,追加到输出序列的末尾。


4. 完整代码实现

以下是基于 C 语言的完整实现,使用malloc动态分配内存以应对 n高达 10^6 的数据规模,避免函数栈溢出:

#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>intmain(){intn;scanf("%d",&n);// 堆分配数组,不占用函数栈,无全局变量int*P=(int*)malloc(sizeof(int)*(n+2));int*suf_max=(int*)malloc(sizeof(int)*(n+2));int*stk=(int*)malloc(sizeof(int)*(n+2));inttop=0;// 读取入栈序列for(inti=0;i<n;i++){scanf("%d",&P[i]);}// 倒序预处理后缀最大值suf_max[n]=0;for(inti=n-1;i>=0;i--){suf_max[i]=(P[i]>suf_max[i+1])?P[i]:suf_max[i+1];}intptr=0;for(inti=0;i<n;i++){stk[top++]=P[i];// 当前元素先入栈ptr=i+1;// ptr指向下一个即将入栈的元素位置// 核心贪心判断:栈顶大于等于后续所有未入栈元素最大值,立即弹出while(top>0&&stk[top-1]>=suf_max[ptr]){// 处理输出格式,避免结尾多余空格if(ptr==n&&top==1)printf("%d",stk[--top]);elseprintf("%d ",stk[--top]);}}// 弹出栈内剩余元素while(top>0){if(top==1)printf("%d",stk[--top]);elseprintf("%d ",stk[--top]);}// 释放堆内存,避免内存泄漏free(P);free(suf_max);free(stk);return0;}

5. 复杂度分析

环节复杂度说明
时间复杂度O(n)预处理后缀最大值遍历一次 O(n);每个元素最多入栈一次、出栈一次,模拟过程也是 O(n)。
空间复杂度O(n)需要三个大小为 n 的数组来存储排列、后缀最大值和模拟栈。

6. 关键设计总结

  • 后缀最大值是灵魂:它将“未来的信息”提前计算好,把原本需要暴力搜索的 O(n^2) 复杂度优化到了 O(n),使得贪心决策可以在常数时间内完成。
  • 贪心策略的本质:栈顶元素只有在“后面不可能出现比它更大的数”时才弹出。这既保证了不会阻塞更大元素的输出,又让较大的数尽可能早地出现在输出序列中,从而最大化字典序。
  • 工程实践细节:代码中使用malloc动态分配内存并在使用后free,避免了在 n较大时发生栈溢出(Stack Overflow)和内存泄漏,是处理大规模数据时的良好习惯。
http://www.jsqmd.com/news/1132066/

相关文章:

  • DB2 11.5 Windows 10 安装避坑 3 要点:家庭版系统安全性与驱动下载
  • 机器人产业演进逻辑与商业化落地全景攻略
  • 从演示到生产:AI 编程工具链在大模型应用落地中的工程化实践
  • 知识加工模块与博客工厂模块的状态重新定义
  • 一年之后,重新理解 AI 编程
  • 2026北京活动策划公司口碑榜与政企会务优选指南
  • SQL注入编码绕过技术详解:从URL编码到宽字节注入
  • 【嵌入式C语言】07.二级指针+函数
  • Unity UGUI ScrollRect 与 Mask 组合:5个高级交互效果实现(含惯性/回弹)
  • AI CLI 流式渲染:边输出边保存,别只顾炫酷
  • 第18周周报
  • 你的 AI Agent 会在服务器上“修仙“——OpenClaw.NET 长持久会话技术解读
  • x64dbg 逆向实战:3步定位小程序密码验证逻辑并绕过(附修改汇编指令)
  • 豆包和通义千问智能体突遭下线——AI拟人化监管正式落地,影响有多大?
  • 入驻 APA 大湾区模型秀能接触哪些精准客群?
  • VIA键盘配置工具:3个场景教你打造专属机械键盘工作流
  • 本周液冷五件事 #6(6/29—7/5)
  • Windows C++编译 Paddle Inference 3.5.0 GPU 版本完整指南
  • 通信与接口协议面试七、RS232
  • Dragonfly2安全机制深度剖析:TLS证书与OAuth2访问控制实战
  • 卡梅德生物技术快报|构建噬菌体肽库:全质粒 PCR 克隆优化、NGS 序列偏倚分析与淘选数据定量解析
  • 某次热身赛re方向wp
  • MySQL库与表的操作
  • 在成都买翡翠,不同段位该去哪家店
  • 3步彻底解决Sublime Text中文乱码:ConvertToUTF8插件终极解决方案
  • 9大网盘直链解析工具:开源解决方案如何提升工作效率300%
  • TD3 vs SAC vs DDPG:3 种连续控制算法在 5 个 MuJoCo 任务上的性能对比
  • openEuler 22.03 LTS 配置华为云镜像源:3步完成并验证可用性
  • GPT-4o 翻译质量评测:8篇大学英语课文英译中,BLEU得分与人工评估对比
  • C盘红了不敢乱删?这个开源工具让AI帮你判断哪些文件夹能删