https://leetcode-cn.com/problems/sliding-window-maximum/

    1. class Solution {
    2. public int[] maxSlidingWindow(int[] nums, int k) {
    3. // 时间复杂度:O(N)
    4. // 空间复杂度:O(N)
    5. // 双向队列
    6. int[] resArray = new int[nums.length - k + 1];
    7. // 定义双向队列,保存元素的索引
    8. // 每来一个元素,总要得到当前最大值,但是不是总固定保留 k 个元素,
    9. // 只把之前所有比当前元素小的那个数全部删掉
    10. // 队列每一论迭代只保留,从大到小、递减的一个队列
    11. // 更新原则为:保存 “ 更新更大 ” 的元素
    12. // 两个操作结合,队首可能需要删除、队尾可能需要添加
    13. ArrayDeque<Integer> deque = new ArrayDeque<>();
    14. // 初始化
    15. for (int i = 0; i < k; i++) {
    16. // 如果队尾元素小于当前元素,直接删除
    17. while (!deque.isEmpty() && nums[i] > nums[deque.getLast()]) {
    18. deque.removeLast();
    19. }
    20. deque.addLast(i);
    21. }
    22. resArray[0] = nums[deque.getFirst()];
    23. // 遍历数组所有元素,作为窗口的结束位置,
    24. for (int i = k; i < nums.length; i++) {
    25. // 判断,如果需要删掉的就是上一个窗口最大值,那么需要将队列中的最大值删掉
    26. // 因为窗口必须移动
    27. if (!deque.isEmpty() && deque.getFirst() == i - k) {
    28. deque.removeFirst();
    29. }
    30. // 判断新增元素是否可以删除队尾元素
    31. // 如果队尾小于当前元素,直接删除
    32. while (!deque.isEmpty() && nums[i] > nums[deque.getLast()]) {
    33. deque.removeLast();
    34. }
    35. deque.addLast(i);
    36. // 保存结果
    37. resArray[i - k + 1] = nums[deque.getFirst()];
    38. }
    39. return resArray;
    40. }
    41. }

    image.png

    1. class Solution {
    2. public int[] maxSlidingWindow(int[] nums, int k) {
    3. // 时间复杂度:O(N)
    4. // 空间复杂度:O(N)
    5. int n = nums.length;
    6. // 定义结果数组
    7. int[] resArray = new int[n - k + 1];
    8. // 定义存放块内最大值的 left 和 right 数组
    9. int[] left = new int[n];
    10. int[] right = new int[n];
    11. // 左右扫描
    12. for (int i = 0; i < n; i++) {
    13. // 从左至右
    14. if (i % k == 0) {
    15. // 初始位置
    16. left[i] = nums[i];
    17. } else {
    18. // 不是起始位置,直接和 left[i-1] 比较取较大值
    19. left[i] = Math.max(left[i - 1], nums[i]);
    20. }
    21. // 从右至左
    22. int j = n - 1 - i;
    23. // 块中的最右边或者本身就是最右边元素
    24. if (j % k == k - 1 || j == n - 1) {
    25. // 初始位置
    26. right[j] = nums[j];
    27. } else {
    28. // 不是起始位置,直接和 right[j+1] 比较取较大值
    29. right[j] = Math.max(right[j + 1], nums[j]);
    30. }
    31. }
    32. // 再次扫描一次,对每个窗口取最大值
    33. for (int i = 0; i < n - k + 1; i++) {
    34. resArray[i] = Math.max(right[i], left[i + k - 1]);
    35. }
    36. return resArray;
    37. }
    38. }

    优先队列:

    优先级队列中,数据按关键词有序排列,插入新数据的时候,会自动插入到合适的位置保证队列有序。(顺序有两种形式:升序或者是降序) 比如我们往队列里面插入132,插入2的时候,就会在内部调整为123(默认顺序是升序)。正是由于这个优良特性可以帮助我们实现一系列问题。

    针对降序,在新建优先队列时要:

    1. // 使用优先队列,实现大顶堆
    2. PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
    3. @Override
    4. public int compare(Integer o1, Integer o2) {
    5. return o2 - o1;
    6. }
    7. });

    双向队列

    1. class Solution {
    2. public int[] maxSlidingWindow(int[] nums, int k) {
    3. int[] res = new int[nums.length - k + 1];
    4. // 保存索引
    5. ArrayDeque<Integer> deque = new ArrayDeque();
    6. // 第一轮
    7. for (int i = 0; i < k; i++) {
    8. while (!deque.isEmpty() && nums[i] > nums[deque.getLast()]) {
    9. deque.removeLast();
    10. }
    11. deque.add(i);
    12. }
    13. res[0] = nums[deque.getFirst()];
    14. for (int i = k; i < nums.length; i++) {
    15. if (!deque.isEmpty() && deque.getFirst() == i - k) {
    16. deque.removeFirst();
    17. }
    18. while (!deque.isEmpty() && nums[i] > nums[deque.getLast()]) {
    19. deque.removeLast();
    20. }
    21. deque.addLast(i);
    22. res[i - k + 1] = nums[deque.getFirst()];
    23. }
    24. return res;
    25. }
    26. }

    左右指针