zoukankan      html  css  js  c++  java
  • 600.奶牛的仰望

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

    一、题目描述

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

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

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

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

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

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

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

    数据范围
    (1≤N≤10^5)
    (1≤H_i≤10^6)

    输入样例:

    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;
    }
    
  • 相关阅读:
    上传图片并压缩
    一张图教会你es6
    字符串生成二维码
    city-picker城市选择,三级联动
    jquery本地文件
    前端颜色选择器
    某音乐api
    js正则那些事
    Android判断网络是否打开,并打开设置网络界面
    execute、executeQuery和executeUpdate之间的区别 转
  • 原文地址:https://www.cnblogs.com/littlehb/p/15247842.html
Copyright © 2011-2022 走看看