坚持第22天,加油!!!
题目
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
示例 3:
输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:
输入:nums = [9,11], k = 2
输出:[11]
示例 5:
输入:nums = [4,-2], k = 2
输出:[4]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
代码
最开始并不觉得难,觉得用队列就行了,但是运行超时,因为在窗口中选最大值我选的方法不当(遍历比较),后来又改了一下,结果直接结果错了。(代码为反面案例)
class Solution {
public int midmax=Integer.MIN_VALUE;
public int[] maxSlidingWindow(int[] nums, int k) {
//Queue<Integer> queue = new LinkedList<Integer>();
Deque<Integer> deque = new LinkedList<Integer>();
List<Integer> list=new ArrayList<Integer>();
int count=0;
int max;
for(int i=0;i<nums.length;i++)
{
if(count<k)
{
deque.offerLast(nums[i]);
count++;
System.out.println("count"+count+" "+deque);
if(count==k)
{
max=maxq(deque,midmax);
System.out.println(" "+deque+"max"+max+"midmax"+midmax);
list.add(max);
deque.pollFirst();
count--;
}
}
}
return list.stream().mapToInt(Integer::valueOf).toArray();
}
int maxq(Deque<Integer> deque,int number)
{
int max=Integer.MIN_VALUE;
if(number==Integer.MIN_VALUE)
{
int newd=deque.removeFirst();
System.out.println(deque);
for(Integer num:deque)
{
midmax=Math.max(midmax,num);
// System.out.println("midmax"+midmax+"num"+num);
}
max=Math.max(midmax,newd);
System.out.println("midmax"+midmax+"max"+max);
deque.addFirst(newd);
}else{
midmax=number;.offerLast
max=Math.max(deque.peekLast(),number);
}
return max;
}
}
反思
1、队列中的双端队列的使用
2、好的思路:(以后注意选择最值,考虑优先队列(堆)、单调队列、栈)
1)优先队列(堆)
优先队列需要自定义排序方法,注意队列中存的是数组(nums[i],i)。优先队列自己在push,pop都会进行堆的重构。因此peek()就是堆的最值。过程就是将新的元素入堆push,然后判断peek对应的序号是不是在窗口内,若在则peek()就是最值,若不是则pop出,直至出现在窗口内的最值。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] pair1, int[] pair2) {
return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
}
});
for (int i = 0; i < k; ++i) {
pq.offer(new int[]{nums[i], i});
}
int[] ans = new int[n - k + 1];
ans[0] = pq.peek()[0];
for (int i = k; i < n; ++i) {
pq.offer(new int[]{nums[i], i});
while (pq.peek()[1] <= i - k) {
pq.poll();
}
ans[i - k + 1] = pq.peek()[0];
}
return ans;
}
}
2)单调队列,单调队列在push的操作和一般队列不一样,从而保证了单调性。单调队列还有max()方法返回最值也是peek(),其pop方法和一般的队列也不一样。
class Solution {
private class MonotonicQueue{
Deque<Integer> deque;
public MonotonicQueue(){
deque=new ArrayDeque<Integer>();
}
public Integer max(){
return deque.peekFirst();
}
public void pop(int num){
if(!deque.isEmpty() && num==deque.peekFirst())
deque.pollFirst();
}
public void push(int num){
while(!deque.isEmpty() && deque.peekLast()<num){
deque.pollLast();
}
deque.addLast(num);
}
}
public int[] maxSlidingWindow(int[] nums, int k) {
MonotonicQueue windows = new MonotonicQueue();
ArrayList<Integer> res = new ArrayList<>();
for(int i=0;i<nums.length;i++){
if(i < k - 1){
windows.push(nums[i]);
}else{
windows.push(nums[i]);
res.add(windows.max());
windows.pop(nums[i-k+1]);
}
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
}