欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 【单调栈】-----【Look Up S】

【单调栈】-----【Look Up S】

2025/6/22 9:09:25 来源:https://blog.csdn.net/2401_82676816/article/details/148795482  浏览:    关键词:【单调栈】-----【Look Up S】

P2947 [USACO09MAR] Look Up S

题目链接

题目描述

约翰的 N ( 1 ≤ N ≤ 10 5 ) N(1\le N\le10^5) N(1N105) 头奶牛站成一排,奶牛 i i i 的身高是 H i ( 1 ≤ H i ≤ 10 6 ) H_i(1\le H_i\le10^6) Hi(1Hi106)。现在,每只奶牛都在向右看齐。对于奶牛 i i i,如果奶牛 j j j 满足 i < j i<j i<j H i < H j H_i<H_j Hi<Hj,我们可以说奶牛 i i i 可以仰望奶牛 j j j。 求出每只奶牛离她最近的仰望对象。

输入格式

1 1 1 行输入 N N N,之后每行输入一个身高 H i H_i Hi

输出格式

N N N 行,按顺序每行输出一只奶牛的最近仰望对象,如果没有仰望对象,输出 0 0 0

输入输出样例 #1

输入 #1

6 
3 
2 
6 
1 
1 
2

输出 #1

3 
3 
0 
6 
6 
0

说明/提示

【输入说明】 6 6 6 头奶牛的身高分别为 3,2,6,1,1,2。

【输出说明】奶牛 1,2 仰望奶牛 3,奶牛 4,5 仰望奶牛 6,奶牛 3 和 6 没有仰望对象。

【数据规模】
对于 20 % 20\% 20% 的数据: 1 ≤ N ≤ 10 1\le N\le10 1N10
对于 50 % 50\% 50% 的数据: 1 ≤ N ≤ 10 3 1\le N\le10^3 1N103
对于 100 % 100\% 100% 的数据: 1 ≤ N ≤ 10 5 , 1 ≤ H i ≤ 10 6 1\le N\le10^5,1\le H_i\le10^6 1N105,1Hi106

题解(单调栈)

单调栈原理见本文

一、问题抽象与分析

我们的问题本质是:对于每个位置 i i i,找出 j > i j > i j>i H j > H i H_j > H_i Hj>Hi 的最小 j j j

这正是一个经典的 “下一个更大元素”(Next Greater Element)问题:

  • 每个元素向右寻找第一个比它大的元素;
  • 单调栈可以在 O ( n ) O(n) O(n) 时间内高效求解。

二、算法思路(单调栈)

我们从右向左遍历整个数组,维护一个单调递减栈(栈中下标对应的身高递减):

栈的含义:

  • 栈中保存的是还没有“被任何左边的奶牛仰望”的奶牛;
  • 栈顶始终是右边最靠近的、可能被当前奶牛仰望的候选对象;
  • 一旦发现栈顶的奶牛身高 ≤ H i \le H_i Hi,就说明它无法成为 i i i 的仰望对象,弹出。

维护逻辑:

  1. i = n i = n i=n 1 1 1 逆序扫描每头奶牛;

  2. 对于每头奶牛:

    • 弹出所有比它矮或一样高的牛(这些牛无法被仰望);
    • 栈顶的奶牛就是她可以仰望的最近牛(如果栈非空);
    • 当前奶牛入栈,作为左边牛的候选仰望对象。

三、完整代码:

#include <bits/stdc++.h>
using namespace std;int main()
{int n;// 输入奶牛的数量 n(编号从 1 到 n)cin >> n; // 奶牛的身高数组,height[i] 表示第 i 头奶牛的身高(从下标 1 开始)vector<int> height(n + 1); for (int i = 1; i <= n; i++){// 依次读入每头奶牛的身高cin >> height[i]; }// 单调递减栈,栈中存的是奶牛编号(从右往左维护)stack<int> stk;  // answer[i] 表示奶牛 i 最近能仰望的奶牛编号(若无则为 0)               vector<int> answer(n + 1, 0);   // 从右往左扫描每头奶牛for (int i = n; i >= 1; i--){// 弹出所有“不够高”的奶牛,因为它们不可能成为当前奶牛的仰望对象while (!stk.empty() && height[stk.top()] <= height[i]){stk.pop();}// 此时栈顶就是右边第一个比当前奶牛高的奶牛(如果栈不为空)answer[i] = stk.empty() ? 0 : stk.top();// 当前奶牛编号入栈,作为后面奶牛的“潜在仰望对象”stk.push(i);}// 输出答案,每行一个:第 i 行表示第 i 头奶牛仰望的奶牛编号(或者 0)for (int i = 1; i <= n; i++){cout << answer[i] << endl;}return 0;
}

四、复杂度分析

  • 时间复杂度:每个元素最多入栈一次、出栈一次,复杂度为 O ( n ) O(n) O(n)
  • 空间复杂度:使用 O ( n ) O(n) O(n) 额外空间保存答案和单调栈。

五、总结

本题的关键在于右边第一个比它大的元素,这类问题是单调栈的经典应用之一:

类型维护方向栈内单调性典型问题
找右边第一个更大元素右→左单调递减本题 Look Up、柱状图最大矩形
找右边第一个更小元素右→左单调递增维护下一个最小值
找左边第一个更大元素左→右单调递减左边比它大的最近值
找左边第一个更小元素左→右单调递增下一个更小值

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词