600.奶牛的仰望

AcWing题目传送门
洛谷题目传送门

一、题目描述

约翰有N头奶牛,编号为1N

现在这N头奶牛按编号从小到大的顺序站成了一排,其中奶牛 i 的身高为Hi

现在,每头奶牛都向它的右侧望向那些编号较大的奶牛,对于奶牛 i 如果存在一头奶牛 j 满足 i<j 并且 Hi<Hj,那么我们称奶牛 i 需要仰视奶牛 j

请你求出每头奶牛的最近仰视对象。

输入格式
第一行包含整数N

接下来N行,每行包含一个整数Hi,其中第 i 行的数为编号为 i 的奶牛的高度。

输出格式
N 行,每行输出一个整数,其中第 i 行的输出整数表示编号为 i 的奶牛的最近仰视对象的编号,如果不存在仰视对象,则输出0

数据范围
1N105
1Hi106

输入样例:

6 
3  2  6  1  1  2 

输出样例

3 3 0 6 6 0 

二、解题思路

结论:找出离自己最近比自己大(或小)的,用单调栈。

最朴素的办法就是暴力,遍历每一个奶牛,然后向它右边遍历所有其它奶牛,找出离自己最近并且高于自己的奶牛。

这么做性能并不是很高,比如 [1,2,2,2,2,2,2,3,3,3,3,3,3],这样的测试数据,第一个2的那个,需要向右找6个数字才能找到比自己大的;而第二个2,则需要向右找5个数字才能找到比自己大的。

想要性能好,该怎么办呢?我们需要知道为什么朴素作法慢,它到底哪里可提速呢?

很明显,上面的办法中有大量的重复运算,比如明明知道第2个位置和第3个位置一样,结果,还是傻傻的每次去重新开始找,能不慢吗?

单调栈的思路是这样的:
1)设计一个栈,让每个奶牛都带着“我需仰望哪位?”的问题进入栈,一旦有牛能回答这个问题,它就出栈。

2)每个奶牛进栈之前,都与与它最近的已入栈奶牛对比身高,如果它比离它近的高,那么它就是栈顶奶牛的答案:“你需仰望大爷我!”,栈顶的知道答案后,就退出了栈。

3)反复执行上面的过程,把栈顶的奶牛都处理掉,直到栈为空或者栈顶奶牛的高度大于要入栈的奶牛,再把当前的奶牛入栈,因为它自己也想知道答案。

其实单调栈就是解决了两个问题“比你高”,“离你近”。

比你高是靠与栈顶元素对比来的,离你近是因为栈本身的性质。

三、数组模拟栈法

#include <bits/stdc++.h>

//奶牛的仰望
//https://www.cnblogs.com/littlehb/p/15247842.html
using namespace std;
const int N = 101000;

int n;    //多少只奶牛
int a[N]; //每只奶牛的身高
int s[N]; //谁仰望谁

//用数组模拟栈,每一个栈内的元素,都是需要找到“比自己高度大的,离自己最近”的奶牛。
int stk[N]; //内容:序号
int tt;     //指针,默认是0


int main() {
    //优化不可少
    ios::sync_with_stdio(false);
    //读入
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    //奶牛一个个进来,判断新进来的是不是已有奶牛仰望的对象
    for (int i = 1; i <= n; i++) {
        //栈内有奶牛,且身高大于栈顶的奶牛
        while (tt && a[i] > a[stk[tt]]) {
            s[stk[tt]] = i;//仰视对象
            tt--;//出栈
        }
        stk[++tt] = i;//加入栈中,等待找到需它仰视的奶牛。
    }
    for (int i = 1; i <= n; i++) cout << s[i] << endl;//输出即可
    return 0;
}

四、STL栈法

#include <bits/stdc++.h>

//奶牛的仰望
//https://www.cnblogs.com/littlehb/p/15247842.html
using namespace std;
const int N = 101000;

int n;    //多少只奶牛
int a[N]; //每只奶牛的身高
int s[N]; //谁仰望谁
stack<int> stk;

int main() {
    //优化不可少
    ios::sync_with_stdio(false);
    //读入
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    //奶牛一个个进来,判断新进来的是不是已有奶牛仰望的对象
    for (int i = 1; i <= n; i++) {
        //栈内有奶牛,且身高大于栈顶的奶牛
        while (stk.size() && a[i] > a[stk.top()]) {
            s[stk.top()] = i;//仰视对象
            stk.pop();//找到了仰望对象,就不再需要继续找了
        }
        stk.push(i);//加入栈中,等待找到需它仰视的奶牛。
    }
    for (int i = 1; i <= n; i++) cout << s[i] << endl;//输出即可
    return 0;
}
posted @   糖豆爸爸  阅读(110)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2019-09-09 2018年蓝桥杯比赛试题
2019-09-09 redis启动异常处理一例
2016-09-09 C#实现对指定文件夹中文件按修改时间排序
Live2D
点击右上角即可分享
微信分享提示