字节跳动面试题.找到数组中每一个元素左面和右面最近的比它小的值「单调栈」

1.题目描述

给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。

输入描述:

第一行输入一个数字 n,表示数组 arr 的长度。
以下一行输入 n 个数字,表示数组的值

输出描述:

输出n行,每行两个数字 L 和 R,如果不存在,则值为 -1,下标从 0 开始。

示例1

输入

7
3 4 1 5 6 2 7

输出

-1 2
0 2
-1 -1
2 5
3 5
2 -1
5 -1

题目来源:https://www.nowcoder.com/practice/e3d18ffab9c543da8704ede8da578b55?tpId=101&&tqId=33169&rp=1&ru=/activity/oj&qru=/ta/programmer-code-interview-guide/question-ranking

2.解题思路

维护一个从小到大值递增的栈,但是栈中存放的是索引。

遍历数组的每一个元素,

如果当前元素比栈顶(索引对应的数值)小,那么弹出栈顶元素(索引)index,如果此时栈不为空,这个index的离index左侧最近且比它小的元素是新的栈顶,离右侧最近且比它小的元素是当前元素的索引;如果栈为空,这个index的离index左侧最近且比它小的元素是-1,离右侧最近且比它小的元素是当前元素的索引

如果栈为空或者当前元素比栈顶(索引对应的数值)大,那么直接压栈即可。

遍历完所有元素后,如果此时栈不为空,则依次弹出每一个元素(索引)index,如果此时栈不为空,这个index的离index左侧最近且比它小的元素是新的栈顶,离右侧最近且比它小的元素是-1。如果栈为空,这个index的离index左侧最近且比它小的元素是-1,离右侧最近且比它小的元素是-1。

3.代码实现

n=int(input())
arr = list(map(int,input().split()))
res=[[0 for _ in range(2)] for _ in range(n)]
stack=[]
for i in range(n):
    while len(stack)>0 and arr[stack[-1]]>arr[i]:
        index=stack.pop(-1)
        if len(stack)>0:
            res[index][0]=stack[-1]
        else:
            res[index][0]=-1

        res[index][1]=i
    stack.append(i)
while len(stack)>0:
    index=stack.pop(-1)
    if len(stack)>0:
        res[index][0]=stack[-1]
    else:
        res[index][0]=-1
    res[index][1] = -1
for i in range(n):
    print (str(res[i][0])+" "+str(res[i][1]))

4.进阶

给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。

解题思路:

维护一个从小到大值递增的栈,但是栈中存放的是索引组成的列表

遍历数组的每一个元素,

如果当前元素比栈顶(此时栈顶是由索引组成的列表,任意取一个索引,通常取0,对应的数值)小,那么弹出栈顶元素(由所有索引组成的列表)index_list,如果此时栈不为空,这个index_list 的每个index的离index左侧最近且比它小的元素是新的栈顶的列表中的最晚加入的索引,离右侧最近且比它小的元素是当前元素的索引;如果栈为空,这个index_list 的每个index的离index左侧最近且比它小的元素是-1,离右侧最近且比它小的元素是当前元素的索引

如果当前栈不为空且当前元素与栈顶列表中的第0个索引对应的值相等,则在栈顶的列表中压入这个元素的索引。(当有重复元素出现时,一定是要加入到栈顶的)

否则栈为空或者当前元素比栈顶列表索引对应的元素大,为当前这个元素的索引创建一个新的列表,并压入栈中。

遍历完所有元素后,如果此时栈不为空,则依次弹出每一个列表index_list,如果此时栈不为空,这个index_list 的每个index的离index左侧最近且比它小的元素是新的栈顶的列表中的最晚加入的索引,离右侧最近且比它小的元素是-1;如果栈为空,这个index_list 的每个index的离index左侧最近且比它小的元素是-1,离右侧最近且比它小的元素是-1

代码实现:

n=int(raw_input())
arr = list(map(int,raw_input().split()))
res=[[0 for _ in range(2)] for _ in range(n)]
stack=[]
for i in range(n):
    while len(stack)>0 and arr[stack[-1][0]]>arr[i]:
        index_list=stack.pop(-1)
        for index in index_list:
            if len(stack)>0:
                res[index][0]=stack[-1][-1]
            else:
                res[index][0]=-1
            res[index][1]=i
    if len(stack)>0 and arr[stack[-1][0]]==arr[i]:
        stack[-1].append(i)
    else:
        stack.append([i])
while len(stack)>0:
    index_list=stack.pop(-1)
    for index in index_list:
        if len(stack)>0:
            res[index][0]=stack[-1][-1]
        else:
            res[index][0]=-1
        res[index][1] = -1
for i in range(n):
    print (str(res[i][0])+" "+str(res[i][1]))

ps:有空为大家画图演示

应用:leetcode739.每日温度「单调栈」

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值