C语言之单调栈

2022-09-04  本文已影响0人  尾枯枝

单调栈

What

单调栈也是栈的一种,满足先进后出的原则,另外,单调栈中的元素是有序的,分为两种

现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。

Why

单调栈在解决一些问题时,比暴力循环方法要简单的多,比如遇到,求一个数组在满足元素比较条件下的统计数据时,可以考虑使用单调栈的做法,典型的就是后面第一次出现大于或者小于当前元素,要计算什么什么的时候。

How

适用单调栈的几个条件:

伪代码如下:

// 此处一般需要给数组最后添加结束标志符,来满足全部出栈
for (遍历这个数组)
{
    if (栈空 || 栈顶元素大于等于当前比较元素)
    {
        入栈;
    } else {
        while (栈不为空 && 栈顶元素小于当前元素) {
            栈顶元素出栈;
            更新结果;
        }
        当前数据入栈;
    }
}
// 如果没有结束标志符,此处要一般要单独判断全部出栈

Example

视野总和

先上题目和代码

/*
描叙:有n个人站队,所有的人全部向右看,个子高的可以看到个子低的发型,给出每个人的身高,问所有人能看到其他人发现总和是多少。
输入:4 3 7 1
输出:2
解释:个子为4的可以看到个子为3的发型,个子为7可以看到个子为1的身高,所以1+1=2
*/
#define STACK_NUM_MAX 500

int VisionSumGet(int *arr, int arrSize)
{
    int stack[STACK_NUM_MAX] = {0}; /* 记录元素位置的单调栈 */
    int top = -1; /* 此单调栈栈顶的索引, 初始位为-1, 栈为空*/
    int sum = 0;

    for (int i = 0; i < arrSize; i++) { /* 遍历数组 */
        while ((top >= 0) && (arr[i] >= arr[stack[top]])) { /* 栈不为空, 且遇到数组元素相等或者大于栈顶对应的数组元素, 则看不到了,进行统计 */
            sum += (i - stack[top] - 1); /* 统计栈顶对应的数组元素看到的人数,并累加*/
            top--; /* 栈顶元素出,判断下一个栈顶元素是否该统计累加 */
        }
        
        top++; /* 把当前的数组元素索引入栈 */
        stack[top] = i;
    }

    /* 最后还要进行一次计算 */
    while (top >= 0) {
        sum += (arrSize - stack[top] - 1);
        top--;
    }

    return sum;
}

首先,套一下单调栈的适用条件

其他可以对照代码注释进行理解。

柱状图中的最大矩形

描述:

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

解释:


Snipaste_2022-09-04_16-25-50.png
Snipaste_2022-09-04_16-26-03.png

同理,首先,套一下单调栈的适用条件

结合代码,可以好好理解一下:

/*
柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
*/

#define STACK_NUM_MAX 100000

int largestRectangleArea(int *heights, int heightsSize)
{
    int stack[STACK_NUM_MAX] = {0}; /* 记录元素位置的单调栈 */
    int top = -1; /* 此单调栈栈顶的索引, 初始位为-1, 栈为空*/
    int max = 0;
    int area = 0;

    for (int i = 0; i < heightsSize; i++) { /* 遍历数组 */
        /* 栈为空, 或者遇到的元素大于等于栈顶对应的元素, 还可以继续向右勾勒*/
        if ((top < 0) || (heights[i] >= heights[stack[top]])) {
            top++;
            stack[top] = i;
            continue;
        }

        /* 栈不为空, 且遇到的元素小栈顶对应的元素, 统计栈顶对应的元素的面积*/
        while ((top >= 0) && (heights[i] < heights[stack[top]])) {
            area = heights[stack[top]] * (i - stack[top]);
            if (area > max) {
                max = area;
            }
            top--; /* 统计栈顶后出栈 */
        }
        /* 保留最后一次的栈顶, 并修改对应的元素的值为当前遇到的元素值, 当前的元素值也不必入栈, 因为它统计的面积必然小一些*/
        top++;
        heights[stack[top]] = heights[i];
    }

    /* 最后还要进行一次计算 */
    while (top >= 0) {
        area = heights[stack[top]] * (heightsSize - stack[top]);
        if (area > max) {
            max = area;
        }
        top--;
    }

    return max;
}
上一篇 下一篇

猜你喜欢

热点阅读