数据结构_栈和单调栈

数组模拟栈

代码模板

const int N = 1e6 + 10;
int st[N], tt = -1;

void push(int x) {
    st[++tt] = x;
}

void pop() {
    --tt;
}

bool isempty() {
    return  tt >= 0;
}

void query() {
    cout << st[tt] << endl;
}

单调栈

  • 题目描述1: 给定一个长度为N的整数数列,输出每个数++左边++++第一个比它小的数++,如果不存在则输出-1。

暴力做法(TLE):双指针算法

void solve() {
    for(int i = 0; i < n; i++) {
        int j = i - 1;
        while(j != -1 && st[j] > a[i]) j--;
        if(j) printf("%d ", st[j]);
        else printf("-1 ");
    }
}

单调栈

思路分析:

  • 假设i < j, 而且a[i] > a[j], 如果a[i]满足条件,则a[j]也必然满足条件。
  • 题目要求输出每个数左边第一个比它小的数,因此输出a[j], 而a[i]一定不会用到。
  • 由此可以得出一个规律:在这个题中,只要存在以下这种情况:
i < j

a[i] > a[j]
  • 即下标小,而其数值反而大的情况一定不会采用。
  • 因此我们完全可以不考虑这种数,而把有用的数单独存储起来,可以选择栈这种数据结构
  • 而最终我们得到的栈中的元素都满足这样的规律:单调性
i < j

a[i] < a[j]

代码模板

const int N = 1e6 + 10;
int st[N], tt = 0;
void solve() {
    for(int i = 0; i < n; i++) {
        while(tt && st[tt] >= a[i]) tt--;
        if(tt) printf("%d ", st[tt]);
        else printf("-1 ");
        st[++tt] = a[i];
    }
}
  • 题目描述2:数列中第 i 个元素之后第一个大于a[i]的元素的下标
const int N = 3e6 + 10; // 根据题目数据范围
int st[N], a[N], ans[N], tt = 0; // 数组模拟的栈从下标为1开始存储

void solve() {
	int n; scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for(int i = n; i >= 1; i--) {
		while(tt && a[st[tt]] <= a[i]) tt -- ; // 删去比当前位置的数小的,剩下第一个比当前的数大的
		ans[i] = (tt) ? st[tt]: 0;
		st[++tt] = i;
	}
	for(int i = 0; i < n; i++) printf("%d ", ans[i]);
}
原文地址:https://www.cnblogs.com/Hot-machine/p/13191638.html