O(N) 算法
- 将输出数组初始化为全 -1。
- 为我们在输入数组中访问过但在输出数组中不知道答案的项目创建一个空的索引堆栈。
- 遍历输入数组中的每个元素:
- 它是否小于堆栈顶部索引的项目?
- 是的。这是第一个这样的元素。在我们的输出数组中填入对应的元素,从栈中取出该项,然后重试,直到栈为空或者答案是否定的。
- 没有。继续 3.2。
- 将此索引添加到堆栈中。从 3 继续迭代。
Python 实现
def find_next_smaller_elements(xs):
ys=[-1 for x in xs]
stack=[]
for i,x in enumerate(xs):
while len(stack)>0 and x<xs[stack[-1]]:
ys[stack.pop()]=x
stack.append(i)
return ys
>>> find_next_smaller_elements([4,2,1,5,3])
[2, 1, -1, 3, -1]
>>> find_next_smaller_elements([1,2,3,4,5])
[-1, -1, -1, -1, -1]
>>> find_next_smaller_elements([5,4,3,2,1])
[4, 3, 2, 1, -1]
>>> find_next_smaller_elements([1,3,5,4,2])
[-1, 2, 4, 2, -1]
>>> find_next_smaller_elements([6,4,2])
[4, 2, -1]
说明
工作原理
这是有效的,因为每当我们向堆栈中添加一个项目时,我们都知道它的值大于或等于堆栈中的每个元素。当我们访问数组中的一个元素时,我们知道如果它低于堆栈中的any项,那么它一定低于堆栈中的last项,因为最后一项必须是最大的。所以我们不需要在堆栈上进行任何类型的搜索,我们可以只考虑最后一项。
注意:只要添加最后一步清空堆栈并使用每个剩余索引将相应的输出数组元素设置为-1,就可以跳过初始化步骤。在 Python 中创建它时将其初始化为 -1 更容易。
时间复杂度
这是 O(N)。主循环清楚地访问每个索引一次。每个索引只添加到堆栈一次,最多删除一次。
作为面试题解决
这种问题在面试中可能会非常令人生畏,但我想指出,(希望如此)面试官不会期望你的脑海中会出现完整的解决方案。通过您的思考过程与他们交谈。我的是这样的:
- 数字的位置与其在数组中的下一个较小数字之间是否存在某种关系?了解其中一些是否会限制其他可能是什么?
- 如果我在白板前,我可能会画出示例数组并在元素之间画线。我也可以将它们绘制为 2D 条形图 - 水平轴是输入数组中的位置,垂直轴是值。
- 我有一种预感,这会显示一个图案,但手头没有纸。我认为图表会很明显。仔细想来,线条不会随意重叠,只会嵌套。
- 在这一点上,我突然想到,这与 Python 内部用于将缩进转换为 INDENT 和 DEDENT 虚拟标记的算法非常相似,这是我之前读过的。请参阅“编译器如何解析缩进?”在此页面上:http://www.secnetix.de/olli/Python/block_indentation.hawk 但是,直到我真正制定出一个算法,我才跟进这个想法并确定它实际上是相同的,所以我认为它没有太大帮助。不过,如果您发现与您知道的其他问题有相似之处,最好提及它,并说明它的相似之处和不同之处。
- 从这里开始,基于堆栈的算法的一般形式变得明显,但我仍然需要多考虑一下,以确保它适用于那些没有后续较小元素的元素。
即使您没有提出可行的算法,也请尝试让面试官了解您的想法。通常,他们感兴趣的是思考过程而不是答案。对于一个棘手的问题,未能找到最佳解决方案但表现出对问题的洞察力可能比知道固定答案但无法给出太多答案要好分析。