【单调栈】解决含有相同元素的单调栈

本文介绍了在单调栈中处理含有相同值的情况,通过链表链接下标,探讨了新元素的处理策略和弹出时的更新方法。通过实例和代码详细展示了有重复值单调栈的实现过程,并强调了无重复值特殊情况下的处理区别。
摘要由CSDN通过智能技术生成

上篇文章我们讨论了单调栈的相关知识,并给出了 不含相同值的单调栈 如何实现的代码。(还没看过上篇文章的赶快 点我 查看哦!)

本文我们继续深入学习,思考 含有相同值的单调栈 如何实现。


由已知推未知:没有相同值的单调栈中我们存放的是各元素的下标。因此,当含有相同值时,它们的 下标是不一样的 ,我们用链表将 相同值 的元素 下标链接起来

此时单调栈中存放的就是一个一个的 链表 了。

实现思路

上次我们寻找的是两侧最近且大于某个数的,这次我们换成 寻找最近且小于某个数 的(其实本质都一样,换个“>”、"<"号即可)。(栈底小 -> 栈顶大)

新元素的处理: 当一个新元素到来时,先与栈顶元素进行比较。

  • 若比栈顶元素大:创建一个新的链表后直接压栈保存;
  • 若比栈顶元素小:需要弹出栈顶链表中所有元素,直到栈空或比栈顶元素大后压栈。
  • 若遇到相同大小时:加入到链表尾部。

弹出时更新信息: 当弹出栈顶元素时,此时次栈顶元素和新来元素就是所求的左右两侧距离最近的且小于该元素的值,更新该链表中所有元素信息

没看懂!没关系,看图例:

注意: 栈中存放的是元素的下标。

代码

public static int[][] getNearLess(int[] arr) {
    int n = arr.length;
    int[][] res = new int[n][2];
    // 链表栈
    Stack<List<Integer>> stack = new Stack<>();
    for (int i = 0; i < n; i++) {
        while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
            List<Integer> popls = stack.pop();
            int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
            for (Integer popi : popls) {
                res[popi][0] = leftLessIndex;
                res[popi][1] = i;
            }
        }
        // 相等时加入
        if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
            stack.peek().add(Integer.valueOf(i));
        } else {
        // 小于时,新增一个链表,加入栈顶
            ArrayList<Integer> list = new ArrayList<>();
            list.add(i);
            stack.push(list);
        }
    }
    while (!stack.isEmpty()) {
        List<Integer> popls = stack.pop();
        // 从链表尾部依次弹出
        int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
        for (Integer popi : popls) {
            res[popi][0] = leftLessIndex;
            res[popi][1] = -1;
        }
    }
    return res;
}

代码解释

和上篇文章代码非常类似,只是这次栈中存放的是 下标链表,需要注意以下几点:

  1. 新到元素与栈顶元素相等时,加入到栈顶链表的 链表尾部
  2. 新到元素大于栈顶元素时,生成一个新的链表 后再入栈(此时只有一个元素的链表);
  3. 新到元素小于栈顶元素时,栈顶链表全部出栈,并记录信息。
  4. 当无新元素到来时,也需要出栈。栈顶链表 出栈的顺序从链表尾部依次弹出 !!!

总结

这两篇文章的学习,我们了解了对于 无重复值有重复值 两种不同类型的单调栈的处理方式。

通过一步一步的图例,相信小伙伴们已经掌握了这两种最基本的单调栈思路和代码。

可能有的小伙伴有疑问了,无重复值不是可以看做特殊的有重复值么,那所有的都用有重复值的代码不就行了么?接下来我们将通过一些单调栈的题目体会这两种不同类型的区别。

~ 点赞 ~ 关注 ~ 评论 ~ 不迷路 ~!!!

关注回复「ACM紫书」获取 ACM 算法书籍~

点赞👍评论👀分享🤩

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值