输出每个数左边第一个比它大的数 -输出每个数右边第一个比它小的数

108 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情

输出每个数左边第一个比它大的数

做法:如果当前数比栈顶大,因为它更靠右,所以栈顶就没用了

  • 当前数>=栈顶元素,弹出栈顶元素, 不断处理,直到栈为空 或者 当前数< 栈顶元素
  • 如果栈为空,那么当前数的左边第一个比它大的数就不存在,它本身就是当前[0,i]范围元素的最大值
  • 如果当前数< 栈顶元素 ,那么此时的栈顶元素就是左边第一个比当前元素大的数
//输出每个数左边第一个比它大的数
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, x, tt = -1, s[N]; // tt==-1:表示栈为空
int main() 
{
    cin >> n;
    while (n --) 
    {
        cin >> x;
        //如果当前数比栈顶大,因为它更靠右,所以栈顶元素就没用了
        while (tt != -1 && s[tt] <= x) tt --;
        cout << (tt != -1 ? s[tt] : -1) << ' ';
        s[++ tt] = x;
    }
    return 0;
}

输出每个数右边第一个比它小的数

做法1:逆序遍历,如果当前数比栈顶小,因为它更靠左,所以栈顶就没用了

  • 当前数<=栈顶元素,弹出栈顶元素, 不断处理,直到栈为空 或者 当前数> 栈顶元素
  • 如果栈为空,那么当前数的右边第一个比它小的数就不存在,它本身就是当前[i,n-1]范围元素的最小值
  • 如果当前数> 栈顶元素 ,那么此时的栈顶元素就是右边第一个比当前元素小的数
//输出每个数右边第一个比它小的数 
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, tt = -1,s[N], a[N];
int main() {
    cin >> n;
    for (int i = 0; i < n; i ++) cin >> a[i];
    //逆序遍历,如果当前数比栈顶小,因为它更靠左,所以栈顶就没用了,维护单调递减的栈
    for (int i = n - 1; i >= 0; i --) 
    {
        while (tt!=-1 && s[tt] >= a[i]) tt --;
        a[i] = tt ? s[tt - 1] : -1;
        
        s[++ tt] = a[i];
    }
    for (int i = 0; i < n; i ++) cout << a[i] << ' ';
    return 0;
}

做法2:先逆序,转化为求左边第一个比它小的数,再逆序输出

//求每个数右边第一个比它小的数  等价于 逆序之后,求左边第一个比它小的数
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, tt = -1, s[N], a[N];
int main() 
{
    cin >> n;
    for (int i = n - 1; i >= 0; i --) cin >> a[i];
    //求左边第一个比它小的数
    for (int i = 0; i <= n; i ++) 
    {
        //如果当前数比栈顶小,因为它更靠右,所以栈顶就没用了
        while (tt  != -1&& s[tt] >= a[i]) tt --;
        a[i] = tt ? s[tt - 1] : -1;
        s[++ tt] = a[i];
    }
    //逆序输出答案
    for (int i = n - 1; i >= 0; i --) cout << a[i] << ' ';
    return 0;
}