Leetcode 456 132模式

也是一道筛选单调栈筛选出来的。不知道是因为对单调栈太不熟悉还是为什么,明明标的是中等难度,可是看题解看好久也看不出来个所以然。记录一下个人理解吧(虽然记下来过一段时间应该也会看不懂)。

要找132,可以先简化成遍历各个位置都作为1,然后对于每个位置都向后找到最优的“32”。
什么是最优?其实对于1而言,3的大小并不重要,只要保证2尽可能的大,以至于大于1即可。
可以发现,其实对于范围[a,b]和[x,y],a<x, b>y而言,范围大的解一定是优于或等于范围小的解,所以如果我们从后向前遍历,遍历到每个数字的时候,都维护下从遍历开始至此处的最优解,那么我们在遍历到下一个数字的时候就可以直接将下一个数字当作i了,因为远端的i所处的范围一定是更大的,所以远端的i的解也一定是更优的,所以也就没有必要在还没有遍历到这个i的时候就计算它。所以也就达成了一次计算。

目前剩下的问题就是,如何以O(1)的复杂度,在逆序遍历的过程中维护范围内最优解(即j<k, xj>xk并保证K尽可能的大)

如前文所述,范围大的解优于范围小的解。也就是说在逆序的过程中,我们每扩增一个位置,该新增的位置一定是作为“32”中的3的,也就是最大的那个值。
所以问题就变成了,新增一个位置之后,前面的位置中,最大并且小于新增这个位置的数字是多少,如果比之前的最优解大,那就更新为之前的最优解。直接的想法就是将之前的所有数字都遍历一遍,找出符合条件的最优的数字。但这种做法的复杂度是O(n)不是O(1),有没有更好的方法呢?
上面说的O(n)的方法,是基于维护的是整个范围内的全部数字。由于随着范围的增大,解只会变得更优,所以那些已经曾经是最优解的数字其实已经不重要了,我们维护的数据结构中可以排除它们。这些数字是什么?只要是某个数字后面有大于它的值,它就被求解过,我们就可以排除这些数字。那这个排除的操作什么时候做?其实新增位置的时候就可以做了。当新增位置时,如果比当前数据结构最后一位大,那就代表当前数据结构最后一位要么比最优解小,要么本次作为最优解,既然当过最优解,那这个最后一位就可以删了。相似地,一直遍历直到比最后一位小为止。当新增位置时,如果比当前数据结构最后一位小,就不需要删除操作了。因为前面的那一位一定是没有找到解的(找到解的已经都被删除了)。这里值得注意是,如果这个新增的位置的值比之前找到的最优解小,其实也可以把它删除,因为它不会有贡献(不过宫水题解没判断hhh, 改编之后测了下过了,不过这可能就不叫单调栈了吧哈哈)

又看了下,官方题解讲的好像更清楚,也提出了我的这个优化,思路也和我的差不多W_W,早知道直接看官方题解了,前面那些自己想,想了两个晚上。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

大纲

Share the Post:
滚动至顶部