Blage's Coding Blage's Coding
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
  • 数组

  • 链表

  • 字符串

  • 二叉树

  • 动态规划

  • 深搜回溯

  • 数学贪心

  • 堆栈队列

    • 394.字符串解码
    • 32. 最长有效括号
    • 739. 每日温度
    • 1130. 叶值的最小代价生成树
    • 84. 柱状图中最大的矩形
    • 42.接雨水
    • 85. 最大矩形
    • 239.滑动窗口最大值
    • 6891. 机器人碰撞
    • 445. 两数相加 II
    • 2762. 不间断子数组
      • 1.TreeMap+滑动窗口
      • 2.优先级队列
      • 3.总结
    • 6919. 使数组中的所有元素都等于零
    • 862. 和至少为 K 的最短子数组
    • 1499. 满足不等式的最大值
    • 2856. 删除数对后的最小数组长度
    • 901. 股票价格跨度
    • 2034. 股票价格波动
    • 1488. 避免洪水泛滥
    • 2940. 找到 Alice 和 Bob 可以相遇的建筑
    • 2454. 下一个更大元素 IV
  • 前缀和

  • 算法设计

  • 位运算

  • WA

  • 算法
  • 堆栈队列
phan
2023-07-07
目录

2762. 不间断子数组

# 2762. 不间断子数组 (opens new window)

# 1.TreeMap+滑动窗口

分析:滑动窗口内使用TreeMap维护子数组的最大值,最小值。

TreeMap具有如下性质:

  • 插入元素时,在内部会对Key进行排序,默认是升序。
  • 通过firstKey()和LastKey()两个API分别获取第一个key和最后一个key的值(最小key和最大key)
  • cellingKey(K num):返回大于等于num的最小key值;floorKey(K num):返回小于等于num的最大key值
  • pollFirstEntry():删除key最小的元素。

在本题中,key存放nums数组元素,value存放每个元素出现的次数。通过首尾元素的key判断当前子数组是否不间断。每轮记录以left为左指针的最大子数组。

class Solution {
    public long continuousSubarrays(int[] nums) {
       long res=0;
        int left=0;
        TreeMap<Integer,Integer> treemap=new TreeMap<>();
        for(int i=0;i<nums.length;i++){
            treemap.put(nums[i],treemap.getOrDefault(nums[i],0)+1);
            while(treemap.lastKey()-treemap.firstKey()>2){
                res+=i-left;
                if(treemap.get(nums[left])==1) treemap.remove(nums[left]);
                else treemap.put(nums[left],treemap.get(nums[left])-1);
                left++;

            }
        }
        for(int i=left;i<nums.length;i++){
            res+=nums.length-i;
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 2.优先级队列

事实上如果本题想不到使用TreeMap,那么需要设计实现一个数据结构A,并且满足

  1. A中元素根据nums元素排好序,这样才能直接以O(1)的复杂度拿到子数组的上下界
  2. 窗口移动时,因为需要移除边界元素,更新当前子数组的上下界,因此访问元素或者是直接删除操作复杂度需要为O(1)。

这里采用两个优先级队列PriorityQueue进行模拟,一个是递增队列,另一个是递减队列。具体如下:

  • 分别从两个队列取出首元素,即为滑动窗口内的最大值和最小值
  • remove(Object o)直接从队列删除对应元素。(事实上绝大多数数据结构如ArrayList,Deque,map,stack等都提供了这个方法,本质也是遍历一趟数据结构。然而个别数据结构遍历一趟代价比较大,比如先进先出之类的限制,因此虽然都是遍历,但是一般都直接调用对应API)
class Solution {
    public long continuousSubarrays(int[] nums) {
        long res=0;
        PriorityQueue<Integer> qmax=new PriorityQueue<>(new Comparator<Integer>(){
            public int compare(Integer o1,Integer o2){
                return o2-o1;
            }
        });
        PriorityQueue<Integer> qmin=new PriorityQueue<>(new Comparator<Integer>(){
            public int compare(Integer o1,Integer o2){
                return o1-o2;
            }
        });
        int left=0;
        for(int i=0;i<nums.length;i++){
            qmax.offer(nums[i]);
            qmin.offer(nums[i]);
            while(qmax.peek()-qmin.peek()>2){
                qmax.remove(nums[left]);
                qmin.remove(nums[left]);
                left++;
            }
            res+=i-left+1;
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

耗时上很明显堆优先队列要比上一种TreeMap要慢很多,主要在remove操作上,堆删除元素后还需要shiftup和shiftdowm维护整个堆结构;而相比之下二叉红黑树的删除操作会快很多。

# 3.总结

对于需要维护子窗口、子数组的问题,设计数据结构时需要考虑以下几点:

  • 子结构是否需要排序?排序又分几种:
    • 利用数据结构本身的比较器进行排序,比如PriorityQueue。不需要额外删除元素。
    • 基于自身增删操作来维护一个有序的数据结构,比如单调栈stack,单调队列Deque。这种方法往数据结构里添加新的元素后,一般都需要额外的移除操作。且数据结构大小都会小于子数组大小。
  • 是否需要随机增删操作?删除元素时需要删除首尾元素还是指定元素。虽然一般都会提供remove(object)方法,但是时间复杂度相比于删除首尾元素会大很多。
  • 数据结构内保存的元素是什么?就数组而言可能存在几种情况:
    • 保存索引下标。这种方式储存的信息量最大,获取元素对应值直接从nums根据索引访问。
    • 保存元素值。这种方式用的最多,一般用于“元素是否存在”相关的问题。
    • 保存元素出现的次数。
编辑 (opens new window)
#Leetcode#堆栈队列
上次更新: 2023/12/15, 15:49:57
445. 两数相加 II
6919. 使数组中的所有元素都等于零

← 445. 两数相加 II 6919. 使数组中的所有元素都等于零→

Theme by Vdoing | Copyright © 2023-2024 blageCoder
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式