一、题目描述
约翰有(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;
}