剑指 Offer 59 - I. 滑动窗口的最大值——双向链表实现

通过维护一个从大到小排列的双向链表,每次滑动窗口时,从链表队尾添加新元素并移除旧元素,使得在O(1)时间内获取窗口最大值。左右边界范围为i∈[1−k,n+1−k],j∈[0,n−1]。当窗口移动,将nums[i]从队首移除,nums[j+1]插入到链表适当位置。" 133478112,19671764,Android编程:广播监听网络状态,"['Android开发', '网络编程']
摘要由CSDN通过智能技术生成

在这里插入图片描述


思路:
在不考虑使用双向链表的情况下,通过上面的例子最直接可以想到的便是暴力解法,即每滑动一次窗口时都遍历窗口内的值并得出其中最大的值加入到数组中,那么每次遍历窗口的时间复杂度为O(k),k为窗口的长度,那么长度为n的数组总共需要的时间复杂度为O((n+1-k)*k)。

这样固然得出结果,但是否可以在将 “获取窗口内最大值” 的时间复杂度从 O(k)降低至O(1)?

如果要降为O(1)的话,即只需进行一次操作即可获取窗口内的最大值,这里我们可以想到维护一个链表来,并且该链表内的大小顺序是从大(队首)到小(队尾)排序的,那么每次只需从该链表中取出队首元素即可。但这里要注意的是,该链表中的元素必须只包含滑动窗口的元素,因此每次滑动窗口时都要对一些元素进行取舍。

既然我们只能从队首取最大值,那么就应该从队尾添加元素,因此我们选择双向链表来存储相关元素。

这里先明确滑动窗口的左右边界,根据数组长度n,和滑动窗口的长度k,可以得出滑动窗口左右边界的取值为:
左边界范围 i∈[1−k,n+1−k],右边界范围 j∈[0,n−1];

接着要明确如何对双向链表添加和删除元素。因为每次滑动窗口时改变的元素只有nums[i-1]和nums[j+1],我们要考虑的就是当前移动窗口的最大元素就是nums[i],而由于移动了窗口,左边界变为了i+1,此时就需要将nums[i]从队首中移除(队首便是最大元素)。
总结一下就是 若 i > 0,并且队首元素deque.peekFirst()==nums[i-1] => deque.pollFirst()

对于移动窗口后进来的nums[j+1],我们要将其放置在链表中合适的位置(即保持链表中的元素始终是递减的),那么只需循环判断nums[j+1]是否大于队尾元素,如果大于的话则将队尾元素弹出,如果找到了小于的情况则跳出循环并将nums[j+1]加入到队尾
总结一下就是:

while (!deque.isEmpty()&&deque.peekLast()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值