单调栈:数组坡的最大宽度问题 | 豆包MarsCodeAI刷题

189 阅读3分钟

题目链接

数组坡的最大宽度问题

前置知识

栈: 一种变形的数组结构,每次只能对栈顶进行操作

栈顶:数组的最后一个元素

栈底:数组的第一个元素

出栈即删除数组的最后一个元素

入栈则往数组尾部加入一个元素

单调栈: 基于栈结构,维护一个具有单调性的栈,要么是[1,2,3,4] 要么是[4,3,2,1]

如何维护单调性? 举个例子 我们要构造出一个单调递减栈

nums = [5,6,3,2,7] ,st代表栈
遍历nums, 因为栈中没有元素 我们先入栈5 st = [5]
nums[i] = 6 此时栈顶元素为 5 不大于6 所以不入栈
nums[i] = 3 此时栈顶元素为 5 大于 3, 入栈3,st = [5,3],此时栈顶为3
nums[i] = 2 此时栈顶元素为 3 大于 2, 入栈3,st = [5,3,2],此时栈顶为2
nums[i] = 7 此时栈顶元素为 2 不大于 7, 不入栈
循环结束,单调递减栈为 [5,3,2]

解题思路

  1. 分析题目,简化题意:我们需要找到一个最长的区间,满足左端点小于右端点即可

  2. 我们贪心来思考一下,怎么样会最大化这个区间? 必然是左端点尽量靠左 右端点尽量靠右

  3. 为什么不能双指针? 因为数组无序,不具备单调性

  4. 那我们想办法去构造出一个有序的集合,在通过类似双指针的思路就可以解决这个问题了!

  5. 我们维护一个值单调递减的栈(也可以数组模拟)st,保证其顺序为[4,3,2,1](存储的是下标即(0,1,2,3)), 然后反序遍历原数组,找到st中比他小的最后一个(不断出栈)

  6. 为什么逆序? 题目要求 i < j, 我们逆序一定满足这个条件 只需要判断 a[i] < a[j]即可

举个例子

A = [6,0,8,2,1,5]
构造st = [0,1] 对应的值为 [6,0]
反序遍历A数组,j作为下标
A[j] = 5时, A[st[n]] = 0 (n代表st最后一个下标) 此时满足题目要求 a[i] < a[j]
记录此时的长度 j - i并出栈,继续往前遍历
A[i] = 1 A[st[n]] = 6 不满足 继续遍历
A[i] = 8 A[st[n]] = 6 满足 但长度并没有A[j]= 5时长,所以答案不变,出栈

func solution(A []int) int {
    //单调递减栈
    st := []int{}
    ans := 0
    for i,v := range A {
        //栈空 或 栈顶元素(前面的最小值)大于了当前元素,加入栈
        if len(st) == 0 || A[st[len(st)-1]] >= v {
            st = append(st, i)
        } 
    }
    
    for i := len(A) - 1; i >= 0; i-- {
        j := i
        //得到前面最远的最小值
        for len(st) > 0 && A[st[len(st)-1]] <= A[i] {
            j = st[len(st)-1]
            st = st[:len(st)-1]
        }
        //记录最长区间
        ans = max(ans, i - j)
    } 
    return ans
}
def solution(A):
    # 单调递减栈
    st = []
    ans = 0
    for i, v in enumerate(A):
        if not st or A[st[-1]] >= v:
            st.append(i)
    
    for i in range(len(A) - 1, -1, -1):
        j = i
        while st and A[st[-1]] <= A[i]:
            j = st[-1]
            st.pop()
        ans = max(ans, i - j)
    return ans

int solution(vector<int>A) {
  // 单调递减栈
  stack<int> st;
  int ans = 0;
  for (int i = 0; i < A.size(); i++) {
    if (st.empty() || A[st.top()] >= A[i]) {
      st.push(i);
    }
  }

  for (int i = A.size() - 1; i >= 0; i--) {
    int j = i;
    while (!st.empty() && A[st.top()] <= A[i]) {
      j = st.top();
      st.pop();
    }
    ans = max(ans, i - j);
  }
  return ans;
}