每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

单调栈

单调栈

  • 今天在干oj的时候借助到了单调栈,琢磨了一下它的特性和应用

  • 本题需要找出arr[i]左/右不小于arr[i]的边界,边界长度 * 高即为一个结果,取出最大值即可,而要获得左右不小于arr[i]的边界,单调栈少不了。
什么是单调栈?
  • 分两种一种单调递增栈,弹出的数据单调递增,一种单调递减栈,弹出的数据单调递减

  • 单调递增栈:栈为空或者小于栈顶元素时入栈

  • 单调递减栈:栈为空或者大于栈顶元素是入栈

应用
  • 在本例题中使用单调递减栈,单调递减栈可以轻松获取到,左边比当前数值小的第一个数字,我们可以通过两次遍历分别获取到左边界和者右边界,能否进行简化呢?答案是肯定的,通过取代最后左边第一个大于当前数字的位置,我们积累了左边界,然后继续遍历,当操作到达结算时机时,即为top元素且大于需入栈的元素,此时我们进行结算。

  • 代码如下:

    for (int i = 0; i < len; i++) {
        if (dq.isEmpty() || rectangles[dq.peekLast()] <= rectangles[i]) {
            dq.offerLast(i);
        } else {
            while (!dq.isEmpty() && rectangles[dq.peekLast()] > rectangles[i]) {
                top = dq.pollLast();
                BigInteger temp = new BigInteger(String.valueOf(i - top)).multiply(new BigInteger(String.valueOf(rectangles[top])));
                res = res.max(temp);
            }
            dq.offerLast(top); //入栈等待右边界出现进行结算
            rectangles[top] = rectangles[i];
        }
    }
    
  • 在本题中还需要获得的教训是需要注意是否需要大数操作

  • 还有一个问题是如何保证所有元素都能被结算,我们可以在数组末尾加-1

应用

  • 本问题类比于视野求取,都是求取当数字右方第一个大于大于当前数字的元素,不同的题型,可能或者求取第一个最大值,或者求取到第一个最大值的距离。
  • 本体解题使用单调递增栈,结算时机是入栈元素大于栈顶元素时,栈顶的下一个最大的数其实就为需入栈元素。
总结
  • 单调栈能够快速获取到一个区间,当前元素是区间的最小值,我们可以利用左边界/或者右边界的索引,也可以利用区间的大小(宽度),例如下面的实例就是获取一个区间中左右边界的索引。

  • 类似于求最大面积的题目,那道题用的是宽度本题使用的就是索引

  • 代码:

    for (int i = 1; i < vs.size(); i++)
    {
        vs[i] = vs[i - 1] + v[i-1]; //预处理获得前n项的和,方便后续根据左右边界索引获得区间和
    }
    v.push_back(-1);
    int top, start, end, ret = 0;
    for (int i = 0; i < v.size(); i++)
    {
        if (st.empty() || v[st.top()] <= v[i])
        {
            st.push(i);
        }
        else
        {
            while (!st.empty() && v[st.top()] > v[i])
            {
                top = st.top();
                st.pop();
                int tmp = vs[i] - vs[top];
                tmp = tmp * v[top];
                if (tmp > ret)
                {
                    ret = tmp;
                    start = top+1;
                    end = i;
                }
            }
            st.push(top);
            v[top] = v[i];
        }
    }
    return ret
    
posted @ 2021-03-13 20:31  雨下整夜~  阅读(70)  评论(0)    收藏  举报