解法都在代码里,不懂就留言或者私信
官方定级hard难度,其实是medium,确实字节考过
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 1) {
return new int[]{nums[0]};
}
/**我们要返回的是一个数组,这个窗口从遍历到第k个元素(下标k-1)的时候就形成了,所以最后返回结果的
长度是n-(k-1)=n-k+1 */
int[] ans = new int[nums.length - k + 1];
/**看题意就知道肯定是滑动窗口了,题目标题就是滑动窗口的最大值,这还有啥说的
我们先定义一个窗口,left表示窗口的左边界(包含),right表示窗口的右边界(不包含)
窗口的有效范围是[left, right)的前闭后开区间,初始窗口是[0,0)
表示窗口内没有值 */
int left = 0;
int right = 0;
/**我们使用双向链表来表示这个窗口,我们这里只求最大值,所以定义一个链表即可
这里链表里存的是下标 */
LinkedList<Integer> maxWindow = new LinkedList<>();
/**遍历数组统计,right每次都++,left只有窗口形成之后才++,所以如果有越界这回事,right肯定比left早越界
所以无需判断left是否越界,这里写<=是为了收集最后一个窗口的最大值*/
while(right <= nums.length) {
/**下面就是要处理加入right之前窗口已经形成的情况了,如果加right之前窗口已经够k个了,那left位置应该淘汰
原来的窗口是[left, right),有效长度是right-left*/
if(right - left == k) {
/**既然窗口够了,那搜集一波最大值 */
ans[left] = nums[maxWindow.peekFirst()];
/**如果left位置是当前窗口最大值,那它出去了最大值就变了 */
if(left == maxWindow.peekFirst()) {
/**把最大值去掉,以后的最大值还是pollFirst */
maxWindow.pollFirst();
}
/**left向右移动,原来的left出窗口 */
left ++;
}
/**如果right已经越界了,那就没有必要进行剩下的了 */
if(right == nums.length) {
break;
}
/**我们当前不管窗口形成还有没有形成,right位置都要入窗口(入链表或者说入队列)
因为链表中的元素是按照从first到last越来越小排列的,所以窗口不为空并且窗口中有小于等于(这里要注意的是等于也要淘汰,等于淘汰的理由是
你在我前面肯定出窗口的时间早于我,即便都不出去,你可以作为最大值的情况我也可以,你早点出去我更是比你更适合当最大值)就淘汰
*/
while(!maxWindow.isEmpty() && nums[maxWindow.peekLast()] <= nums[right]) {
maxWindow.pollLast();
}
/**把小于等于last位置的都淘汰,last位置就可以入窗口了*/
maxWindow.addLast(right);
/**不管窗口够不够,right肯定要右移的 */
right ++;
}
return ans;
}
}