题目描述(这个题考察单调队列)
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
窗口大于数组长度的时候,返回空
方法一:
小知识:队列左边头,右边尾。(我觉得是对的)
deque定义:
双向队列:支持插入删除元素的线性集合
特性:
- 插入、删除、获取操作支持两种形式:快速失败和返回null或true/false
- 既具有FIFO特点又具有LIFO特点,即是队列又是栈
- 不推荐插入null元素,null作为特定返回值表示队列为空
- 未定义基于元素相等的equals和hashCode
插入元素
-
addFirst(): 向队头插入元素,如果元素为空,则发生NPE
-
addLast(): 向队尾插入元素,如果为空,则发生NPE
-
offerFirst(): 向队头插入元素,如果插入成功返回true,否则返回false
-
offerLast(): 向队尾插入元素,如果插入成功返回true,否则返回false
移除元素
-
removeFirst(): 返回并移除队头元素,如果该元素是null,则发生NoSuchElementException
-
removeLast(): 返回并移除队尾元素,如果该元素是null,则发生NoSuchElementException
-
pollFirst(): 返回并移除队头元素,如果队列无元素,则返回null
-
pollLast(): 返回并移除队尾元素,如果队列无元素,则返回null
获取元素
-
getFirst(): 获取队头元素但不移除,如果队列无元素,则发生NoSuchElementException
-
getLast(): 获取队尾元素但不移除,如果队列无元素,则发生NoSuchElementException
-
peekFirst(): 获取队头元素但不移除,如果队列无元素,则返回null
-
peekLast(): 获取队尾元素但不移除,如果队列无元素,则返回null
栈操作
pop(): 弹出栈中元素,也就是返回并移除队头元素,等价于removeFirst()
,如果队列无元素,则发生NoSuchElementException
push(): 向栈中压入元素,也就是向队头增加元素,等价于addFirst()
,如果元素为null,则发生NPE,如果栈空间受到限制,则发生IllegalStateException
写这个:
import java.util.*;
class Solution {
public ArrayList<Integer> maxInWindows(int[] nums, int k) {
if (nums.length == 0 || k == 0 || k > nums.length)
return new ArrayList<>();
Deque<Integer> deque = new LinkedList<>();
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < k; i++) { // 未形成窗口
while (!deque.isEmpty() && deque.peekLast() < nums[i])//队列左边头,右边尾
deque.removeLast();
deque.addLast(nums[i]);
}
list.add(deque.peekFirst());
for (int i = k; i < nums.length; i++) { // 形成窗口后
if (deque.peekFirst() == nums[i - k])//如果相等,说明当前单调队列的第一个数就是当前窗口的最左边的数,把第一个数移掉,窗口向后移动
deque.removeFirst();//如果不相等,就说明滑动窗口的最大值是窗口中的后两个数中的一个数
while (!deque.isEmpty() && deque.peekLast() < nums[i])
deque.removeLast();
deque.addLast(nums[i]);
list.add(deque.peekFirst());
}
return list;
}
}
public class Main {
public static void main(String[] args) {
int[] nums = {8,7,6,5,4,3,2,1};
int size = 3;
Solution p = new Solution();
ArrayList<Integer> res = p.maxInWindows(nums, size);
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i) + " ");
}
}
}
下面的就稍微乱点了
package test;
import java.util.ArrayDeque;
import java.util.ArrayList;
class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> res = new ArrayList<>();
if(size == 0) return res;
int begin;
ArrayDeque<Integer> q = new ArrayDeque<>();
for(int i = 0; i < num.length; i++){
begin = i - size + 1;
if(q.isEmpty())//q是用来存i的,左边是最大值
q.add(i);
else if(begin > q.peekFirst())//begin超过前面的最大值了
q.pollFirst();
while((!q.isEmpty()) && num[q.peekLast()] <= num[i])//因为下面执行完q.pollLast()之后,
//q可能就是空了;还有一个重点:这里的<=的=一定是要的,因为i要往前走
q.pollLast();
q.add(i);
if(begin >= 0)
res.add(num[q.peekFirst()]);
}
return res;
}
}
public class Main {
public static void main(String[] args) {
int[] temp = {2,3,4,2,6,2,5,1};
Solution p = new Solution();
ArrayList<Integer> b = p.maxInWindows(temp,3);
System.out.println("输出中位数"+ b);
}
}
简化版:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums == null || nums.length < 2) return nums;
// 双向队列 保存当前窗口最大值的数组位置 保证队列中数组位置的数值按从大到小排序
LinkedList<Integer> queue = new LinkedList();
// 结果数组
int[] result = new int[nums.length-k+1];
// 遍历nums数组
for(int i = 0;i < nums.length;i++){
// 保证从大到小 如果前面数小则需要依次弹出,直至满足要求
while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]){
queue.pollLast();
}
// 添加当前值对应的数组下标
queue.addLast(i);
// 判断当前队列中队首的值是否有效
if(queue.peek() <= i-k){
queue.poll();
}
// 当窗口长度为k时 保存当前窗口中最大值
if(i+1 >= k){
result[i+1-k] = nums[queue.peek()];
}
}
return result;
}
}
方法二:冒泡排序,找滑动窗口的最大值。
package test;
import java.util.ArrayList;
class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size){
ArrayList<Integer> list = new ArrayList<>();
//边界条件
if (num == null || size <= 0 || size > num.length) {
return list;
}
for (int i = 0; i <= num.length - size; i++) {
int max = num[i];
for (int j = i + 1; j <= i + size - 1; j++) {
if (num[j] > max) {
max = num[j];
}
}
list.add(max);
}
return list;
}
}
public class Main {
public static void main(String[] args) {
int[] temp = {2,3,4,2,6,2,5,1};
Solution p = new Solution();
ArrayList<Integer> b = p.maxInWindows(temp,3);
System.out.println("输出中位数"+b);
}
}