程序员代码面试指南之单调栈结构

本文介绍了如何使用单调栈解决数组中查找每个元素左右最小值的问题。通过分析非递减单调栈的工作原理,可以有效地确定每个元素的左边界和右边界。文中提到,即使存在重复元素,也无需使用stack<list>,简单的stack<int>即可完成任务。代码实现中,当元素入栈时确定左边界,弹出时确定右边界,简化了原书中的复杂操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来《程序员代码面试指南》第2版,作者左程云。

对于一个数组(可能有重复元素),对于每个元素arr[i],找到它左边和右边小于arr[i]且离i最近的元素下标,找不到时返回-1。书中为了克服相同元素带来的麻烦,使用了一个stack<list>,其实不需要,stack<int>即可。

分析:利用一个非递减的单调栈(即允许重复元素的递增栈)。对于任意两个元素arr[j],arr[k],如果j<k,那么如果arr[j]>arr[k],那么对于k及k右边的任意元素,j都不可能是他们的左边界。所以栈里面只需保存左边比自己小的元素,且越往左越小。每个元素arr[i]即将入栈时即可确定它的左边界,如果栈顶元素小于arr[i],那么arr[i]的左边界就是栈顶元素;如果栈顶元素等于arr[i],那么arr[i]的左边界就是栈顶元素的左边界。每个元素弹出的时候即可确定它的右边界,右边界就是即将入栈的那个元素。如果元素最终没有被弹出,说明右边没有比它更小的元素了,那么它的右边界就是默认值-1,这样书中代码最后一部分清空栈的操作也是不需要的了。(书里的代码是在弹出元素的时候同时确定它的左边界和右边界,右边界就是即将入栈的元素,左边界就是弹出后的栈顶元素。)

代码如下:

def getNearLess(arr):
    n = len(arr)
    result = [[-1,-1] for i in range(n)]
    stack = []
    for i in range(n):
        while stack and arr[stack[-1]] > arr[i]:
            popIndex = stack.pop()
            result[popIndex][1] = i
        if stack:
            if arr[stack[-1]] == arr[i]:
                result[i][0] = result[stack[-1]][0]
            else:
                result[i][0] = stack[-1]
        stack.append(i)
    return result
    
print(getNearLess([3,1,3,4,3,5,3,2,2]))

def bruteForce(arr):
    n = len(arr)
    result = [[-1,-1] for i in range(n)]
    stack = []
    for i in range(n):
        for j in range(i-1, -1, -1):
            if arr[j] < arr[i]:
                result[i][0] = j
                break
        for j in range(i+1, n):
            if arr[j] < arr[i]:
                result[i][1] = j
                break
    return result

import random
run = 1000
for i in range(run):
    arr = [random.randint(1,5) for i in range(10)]
    assert bruteForce(arr) == getNearLess(arr)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值