news 2026/11/3 14:26:00

单调栈算法求解最大宽度坡问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单调栈算法求解最大宽度坡问题

1. 问题理解与定义

给定一个整数数组A,坡是元组(i, j),其中i < j且A[i] <= A[j]。这样的坡的宽度为j - i。我们需要在A中找到最大宽度的坡。如果不存在,返回0。

示例1: 输入:[6,0,8,2,1,5] 输出:4 解释:最大宽度的坡出现在(i,j)=(1,5): A[1]=0且A[5]=5且0<=5

示例2: 输入:[9,8,1,0,1,9,4,0,4,1] 输出:7 解释:最大宽度的坡出现在(i,j)=(2,9): A[2]=1且A[9]=1且1<=1

2. 暴力解法分析

最直观的解法是双重循环遍历所有可能的(i,j)对:

int maxWidthRamp(int* A, int ASize) { int max_width = 0; for (int i = 0; i < ASize; i++) { for (int j = i + 1; j < ASize; j++) { if (A[i] <= A[j]) { max_width = fmax(max_width, j - i); } } } return max_width; }

时间复杂度:O(n²) 空间复杂度:O(1)

虽然简单直观,但对于大规模数据(如n=50000)会超时,需要优化。

3. 优化思路:单调栈

观察到坡的起点i需要满足:A[i]是某个递减序列的最小值。我们可以使用单调栈来记录这些候选起点。

3.1 构建单调递减栈

int* buildDecreasingStack(int* A, int ASize, int* stackSize) { int* stack = malloc(ASize * sizeof(int)); *stackSize = 0; for (int i = 0; i < ASize; i++) { if (*stackSize == 0 || A[i] < A[stack[*stackSize - 1]]) { stack[(*stackSize)++] = i; } } return stack; }

3.2 从后向前遍历找最大宽度

int findMaxWidth(int* A, int ASize, int* stack, int stackSize) { int max_width = 0; for (int j = ASize - 1; j >= 0; j--) { while (stackSize > 0 && A[stack[stackSize - 1]] <= A[j]) { max_width = fmax(max_width, j - stack[stackSize - 1]); stackSize--; } } return max_width; }

3.3 完整实现

int maxWidthRamp(int* A, int ASize) { int stackSize; int* stack = buildDecreasingStack(A, ASize, &stackSize); int max_width = findMaxWidth(A, ASize, stack, stackSize); free(stack); return max_width; }

时间复杂度:O(n) 空间复杂度:O(n)

4. 算法正确性证明

  1. 单调栈保证了我们只考虑可能的候选起点i
  2. 从后向前遍历确保找到每个i对应的最远j
  3. 当A[stack.top] <= A[j]时,j是当前i能到达的最远位置

5. 边界情况处理

  • 空数组或单元素数组:直接返回0
  • 完全递减数组:返回0
  • 完全递增数组:返回n-1

6. 复杂度分析

构建单调栈:O(n) 查找最大宽度:O(n) 总体:O(n)

7. 测试用例

void test() { int case1[] = {6,0,8,2,1,5}; assert(maxWidthRamp(case1, 6) == 4); int case2[] = {9,8,1,0,1,9,4,0,4,1}; assert(maxWidthRamp(case2, 10) == 7); int case3[] = {1,1,1,1}; assert(maxWidthRamp(case3, 4) == 3); int case4[] = {5,4,3,2,1}; assert(maxWidthRamp(case4, 5) == 0); printf("All test cases passed.\n"); }

8. 优化技巧

  1. 可以合并两个步骤到一个循环中,减少内存分配
  2. 使用指针操作代替数组索引可能更快
  3. 对于特定数据分布可能有更优解法

9. 实际应用场景

这种算法可以应用于:

  • 股票分析(寻找最大价格上升区间)
  • 信号处理(寻找满足条件的最大时间窗口)
  • 数据流分析(监控满足条件的最大间隔)

10. 扩展思考

  1. 如果要求i < j且A[i] < A[j](严格小于),如何修改?
  2. 如果数组非常大(无法放入内存),如何解决?
  3. 如果要求同时满足多个条件(如A[i] <= A[j]且B[i] >= B[j]),如何扩展?

提示:在实际编码面试中,建议先提出暴力解法,然后逐步优化,解释每一步的思考过程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 14:21:39

RHCE认证考试测试题拆解与实操备考个人总结

1. 先搞清楚这张证书的考试形态 RHCE 这三个字母在运维圈里的分量&#xff0c;不用我多说。但很多人第一次接触它时,脑子里的画面还停留在"选择题、题库、背答案"这套流程上,结果一进考场就懵了——没有选择题&#xff0c;没有单选多选&#xff0c;给你三台机器、一份…

作者头像 李华
网站建设 2026/11/3 14:21:10

开关电源设计辅助工具实战:从需求到上电方案

做电源这行的人大概都有过这样的经历&#xff1a;拿到一个新需求&#xff0c;输入电压范围宽、输出电流不小、板子还要求小体积&#xff0c;然后你打开计算表格&#xff0c;一行行填参数&#xff0c;算占空比、算电感、算电容、算补偿&#xff0c;中间某个参数一改&#xff0c;…

作者头像 李华
网站建设 2026/11/3 14:20:19

计算机二级C++笔试高频语法细节与真题考点拆解

简介&#xff1a;这份PDF面向准备全国计算机二级C等级考试的考生&#xff0c;尤其是需要借助历年真题熟悉题型、检验复习效果的自学者与在校学生。内容以2007年二级笔试试卷为蓝本&#xff0c;整理出20道选择题并附参考答案&#xff0c;考点覆盖变量存储类型&#xff08;auto、…

作者头像 李华
网站建设 2026/11/3 14:20:19

机器学习分类任务中的混淆矩阵设计与优化实践

1. 混淆矩阵基础概念解析 混淆矩阵&#xff08;Confusion Matrix&#xff09;是机器学习分类任务中最基础却至关重要的评估工具。我第一次接触这个概念是在研究生时期的一个图像识别项目中&#xff0c;当时导师指着屏幕上的一个4x4表格说&#xff1a;"这个矩阵能告诉你模型…

作者头像 李华
网站建设 2026/11/3 14:20:16

Java byte数组与String转换:默认编码陷阱与乱码排查

上周帮同事排查一个线上问题&#xff1a;同一段报文&#xff0c;本地跑得好好的&#xff0c;部署到测试环境就变成一串问号和方块。代码翻来覆去看了半小时&#xff0c;最后定位到一行new String(bytes)—— 没写编码&#xff0c;换了个运行环境&#xff0c;默认字符集从 UTF-8…

作者头像 李华
网站建设 2026/11/3 14:20:15

相关性推荐:从召回排序到冷启动的站内流量分发实践

网站做起来之后&#xff0c;最让人难受的一种状态是&#xff1a;流量不算少&#xff0c;页面打开速度也还行&#xff0c;用户点进来逛了两三页就走了&#xff0c;购物车空着&#xff0c;评论区冷清&#xff0c;后台看跳出率一路往上走。这时候团队里一定会有人提一句“上个相关…

作者头像 李华