题目
栈的使用
思路
假设现在有一个栈,我们往这个栈中放入元素,放入元素的顺序为:
2 1 5 3 4
经过入栈出栈之后要能够得到字典序最大的序列,那就要选择尽可能大的数出栈,并且在这个数之后没有再比它大的数了。
因此,我们预处理输入的数据,将每个位置之后的最大值求出来,得到一个数组,比如上面的输入数据,我么可以得到下面的数组:
5 , 5 , 5 , 4 , 4 , − 1 5, 5, 5, 4, 4, -1 5,5,5,4,4,−1
为什么会多一个 − 1 -1 −1 出来呢?这是为了方便处理最后一个输入的数的之后的最大值,这道题没说数据范围,保险起见,将 − 1 -1 −1 设为整数最小值吧。
当然,第一个最大值 5 5 5 也没什么用,毕竟 n n n 个位置中每个位置之后的最大值个数也只有 n n n 个, n + 1 n+1 n+1 个数组元素也没什么意义,但是为了方便,多开辟一个整数的空间又如何呢?
得出最终思路:
- 预处理每个位置之后的最大值,得到最大值数组 m a x max max
- 从左往右遍历输入的元素,先将其入栈,然后循环判断当栈不空时栈顶元素是否大于当前位置之后的最大值,如果大于则出栈
代码
#include <limits.h>
#include <stdio.h>
// 这道题并没有说数据个数
// 下面的个数是恰好合适的(经过测试)
#define N 1000005
// 栈和栈顶指针,stk[top - 1]为栈顶元素
int stk[N], top;
int main(void) {
int n = 0, i = 0;
scanf("%d", &n);
int a[n], max[n + 1];
for (i = 0; i < n; i++) {
scanf("%d", a + i);
}
max[n] = INT_MIN;
for (i = n - 1; i >= 0; i--) {
max[i] = max[i + 1] > a[i] ? max[i + 1] : a[i];
}
int flag = 0;
for (i = 0; i < n; i++) {
// 将当前元素入栈
stk[top++] = a[i];
// 如果当前元素(栈顶元素)比其后面的元素都大的话
// 说明其是当前最大值,应该出栈
while (top && stk[top - 1] > max[i + 1]) {
// 注意输出,最后一个元素的后面没有空格
if (flag) {
// 不是第一个元素
printf(" %d", stk[top - 1]);
} else {
// 是第一个元素
printf("%d", stk[top - 1]);
// 将标志位置位
flag = 114514;
}
// 实际上本题并没有卡这个空格,直接按下面的输出也可以
// printf("%d ", stk[top - 1]);
// 出栈
top--;
}
}
printf("\n");
return 0;
}
上面的代码有个巧妙之处:当输入的元素都遍历完了,较大的元素都出栈了的时候,此时栈中可能还会剩余一些元素,而这里不必单独将栈中的元素出栈。此时指针恰好指向最大值数组的最后一个元素,这个元素是一个负无穷的值,每一个元素都比它大,所以此时栈中的剩余的元素就顺理成章地全部出栈了。