小熊家务帮day10- 门户管理

门户管理

  • 1 门户介绍
    • 1.1 介绍
    • 1.2 常用技术方案
  • 2 缓存技术方案
    • 2.1 需求分析
      • 2.1.1 C端用户界面原型
      • 2.1.2 缓存需求
      • 2.1.3 使用的工具
    • 2.2 项目基础使用
      • 2.2.1 项目集成SpringCache
      • 2.2.2 测试Cacheable
        • 需求
        • Service
        • 测试
      • 2.1.3 缓存管理器(设置过期时间)
      • 2.1.4 测试CachePut(上架)
      • 2.1.5 测试CacheEvict(下架)
    • 2.3 解决缓存常见问题
      • 2.3.1 解决缓存穿透
      • 2.3.2 解决缓存击穿
      • 2.3.3 解决缓存雪崩
      • 2.3.2 解决双写不一致
  • 3 项目缓存的具体实现
    • 3.1 开通区域列表缓存实现
      • 3.1.1 缓存方案
      • 3.1.2 查询缓存实现

1 门户介绍

1.1 介绍

门户是指一个网站或应用程序的主页,它是用户进入这个网站或系统的入口,主页上通常聚合很多的信息,包括内容导航、热点信息等,比如:门户网站的首页、新闻网站的首页、小程序的首页等。

1.2 常用技术方案

实现门户功能用到哪些技术呢?
基于两个需求去分析:
1.门户上的信息是动态的
门户上的信息会按照一定的时间周期去更新,比如一个新闻网站不可能一直显示一样的新闻。
2.门户作为入口其访问频率非常高
对于访问频率高的界面其加载速度是至关重要的,因为它直接影响用户的体验和留存率。一般来说门户网站的首页应该在2至3秒内加载完成,这被认为是一个合理的加载时间目标。

常见的两类门户是:web门户和移动应用门户。
web门户
web门户是最常见的门户类型,比如:新浪、百度新闻等,它们通过PC浏览器访问,用户可以通过桌面电脑、笔记本电脑、平板电脑和智能手机等设备访问。Web门户通常运行在Web浏览器上,用户可以通过输入网址或通过搜索引擎访问。
web门户是通过浏览器访问html网页,虽然html网页上的内容是动态的但是考虑门户作为入口其访问频率非常高所以就需要提高它的加载速度,如果网页上的数据是通过实时查询数据库得到是无法满足要求的,所以针对web门户提高性能的关键是如何提高html文件的访问性能,如何提高查询数据的性能。

流程

  • 将门户页面生成静态网页发布到CDN服务器。
    纯静态网页通过Nginx加载要比去Tomcat加载快很多。
    我们可以使用模板引擎技术将动态数据静态化生成html文件,并通过CDN分发到边缘服务器,可以提高访问效率。

那什么是CDN?
CDN 是构建在数据网络上的一种分布式的内容分发网,旨在提高用户访问网站或应用时的性能。
下图中,通过CDN将内容分发到各个城市的CDN节点上,北京的网民请求北京的服务即可拿到资源,提高访问速度。
在这里插入图片描述

  • html文件上的静态资源比如:图片、视频、CSS、Js等也全部放到CDN服务。
  • html上的动态数据通过异步请求后端缓存服务器加载,不要直接查询数据库,通过Redis缓存提高查询速度。
    在这里插入图片描述
  • 使用负载均衡,通过部署多个Nginx服务器共同提供服务,不仅保证系统的可用性,还可以提高系统的访问性能
  • 在前端也做一部分缓存
    不仅服务端可以做缓存,前端也可以做缓存,前端可以把缓存信息存储到
    LocalStorage: 提供了持久化存储,可以存储大量数据
    SessionStorage: 与 LocalStorage 类似,但数据只在当前会话中有效,当用户关闭标签页或浏览器时清空。
    Cookie: 存储在用户计算机上的小型文本文件,可以在客户端和服务器之间传递数据
    浏览器缓存:通过 HTTP 头部控制,比如:Cache-Control头部提供了更灵活的缓存控制选项,可以定义缓存的最大有效时间。

移动应用门户:
移动应用门户是专为移动设备(如智能手机和平板电脑)设计的应用程序,比如:小程序、APP等,用户可以通过应用商店下载并安装。这些应用程序提供了更好的用户体验,通常具有更高的性能和交互性,可以直接从设备主屏幕启动。
对于移动应用提高访问效率方法通常有:
静态资源要走CDN服务器
对所有请求进行负载均衡
在前端及服务端缓存门户上显示的动态数据。

根据上边的分析,对于Java程序员需要关注的是缓存服务的开发,主流的缓存服务器是Redis,所以我们接下来的工作重点是使用Redis为门户开发缓存服务接口。

2 缓存技术方案

2.1 需求分析

2.1.1 C端用户界面原型

本项目小程序门户首页如下图:
在这里插入图片描述

第1部分:用户允许微信授权后,自动获取当前定位,点击地址进入城市选择页面,如下图:
已开通城市是指在区域管理中所有启用的区域信息。
在这里插入图片描述
第2部分:触发搜索框进入搜索主页面,如下图:
输入关键字搜索服务信息。
在这里插入图片描述
第3部分:首页服务列表
默认展示前两个服务分类,每个服务分类下取前4个服务项(根据后台排序规则显示,如排序相同则按照更新时间倒序排列)
点击一级分类进入【全部服务】页;点击服务项进入【服务项目详情页】

第4部分:热门服务列表
这里显示在区域服务界面设置热门服务的服务项。

第5部分:全部服务
点击首页服务列表的服务分类或直接点击“全部服务”进入全部服务界面,
在这里插入图片描述
全部服务界面,如下图:
在全部服务界面需要展示当前区域下的服务分类,点击服务分类查询分类下的服务。
在这里插入图片描述
点击服务名称进入服务详情页面:
在这里插入图片描述

2.1.2 缓存需求

根据上一小节的需求分析,需要缓存的点如下:

  • 定位界面上的已开通区域列表
  • 首页服务列表
  • 服务搜索(ES)
  • 热门服务列表
  • 服务信息(点击某一个服务,服务的详细信息一部分是服务介绍的图片和内容等,一部分是区域服务信息(比如价格))
  • 服务分类(服务分类下的服务项通过Elasticsearch去查询)

2.1.3 使用的工具

  • 缓存:redis
  • 缓存客户端:Lettuce
  • 缓存访问工具:Spring data redis(RedisTemplete操作redis) 和 SpringCache(注解操作redis)

2.2 项目基础使用

2.2.1 项目集成SpringCache

问:在哪个微服务集成呢?
因为大部分缓存使用都是对于家政服务,因此肯定在家政服务那块微服务进行集成啊

引入依赖

<dependency>
    <groupId>com.jzo2o</groupId>
    <artifactId>jzo2o-redis</artifactId>
</dependency>

在nacos配置shared-redis-cluster.yaml,开发环境使用redis单机,配置文件如下:
在这里插入图片描述

2.2.2 测试Cacheable

执行流程是:第一次查询服务信息缓存中没有该服务的信息此时去查询数据库,查询数据库拿到服务信息并进行缓存,第二次再去查询该服务信息发现缓存中有该服务的信息则直接查询缓存不再去数据库查询。
在这里插入图片描述

需求

实现对区域服务信息查询时进行缓存

Service
    /**
     * 查缓存方法
     * @param id 对应serve表的主键
     * @return
     */
    @Cacheable(value = RedisConstants.CacheName.SERVE,key = "#id")
    @Override
    public Serve queryServeByIdCache(Long id) {
        return getById(id);
    }

测试
    /*
    缓存测试
     */
    @Test
    public void test_queryServeByIdCache(){
        Serve serve = serveService.queryServeByIdCache(1693815623867506689L);
        Assert.notNull(serve,"服务为空");
    }

在这里插入图片描述

2.1.3 缓存管理器(设置过期时间)

虽然数据被成功缓存,如果想调整缓存过期时间怎么做呢?
在@Cacheable注解中有一个属性为cacheManager,表示缓存管理器,通过缓存管理器可以设置缓存过期时间。
我定义了三种缓存管理器:
缓存时间为30分钟、一天、永久,分别对应的bean的名称为:cacheManager30Minutes、cacheManagerOneDay、cacheManagerForever。

    /**
     * 缓存时间30分钟
     *
     * @param connectionFactory redis连接工厂
     * @return redis缓存管理器
     */
    @Bean
    public RedisCacheManager cacheManager30Minutes(RedisConnectionFactory connectionFactory) {
        int randomNum = new Random().nextInt(100);
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(30 * 60L + randomNum))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON_SERIALIZER));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    /**
     * 缓存时间1天
     *
     * @param connectionFactory redis连接工厂
     * @return redis缓存管理器
     */
    @Bean
    public RedisCacheManager cacheManagerOneDay(RedisConnectionFactory connectionFactory) {
        //生成随机数
        int randomNum = new Random().nextInt(6000);
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //过期时间为基础时间加随机数
                .entryTtl(Duration.ofSeconds(24 * 60 * 60L + randomNum))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON_SERIALIZER));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    /**
     * 永久缓存
     *
     * @param connectionFactory redis连接工厂
     * @return redis缓存管理器
     */
    @Bean
    @Primary
    public RedisCacheManager cacheManagerForever(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON_SERIALIZER));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

2.1.4 测试CachePut(上架)

对之前写好的serviceImpl类进行注解即可:

    @Override
    @Transactional
    @CachePut(value = RedisConstants.CacheName.SERVE,key = "#id",cacheManager = RedisConstants.CacheManager.ONE_DAY)
    public Serve onSale(Long id)
    。。。。。。

2.1.5 测试CacheEvict(下架)

    @Override
    @Transactional
    @CacheEvict(value = RedisConstants.CacheName.SERVE,key = "#id")
    public Serve offSale(Long id)

2.3 解决缓存常见问题

2.3.1 解决缓存穿透

本项目就先用最简单的方法:缓存空值或特殊值的方法

1、对请求增加校验机制
比如:查询的Id是长整型并且是19位,如果发来的不是长整型或不符合位数则直接返回不再查询数据库。

2、缓存空值或特殊值
当查询数据库得到的数据不存在,此时我们仍然去缓存数据,缓存一个空值或一个特殊值的数据,避免每次都会查询数据库,避免缓存穿透。

3、使用布隆过滤器
布隆过滤器(Bloom Filter)是一种数据结构,用于快速判断一个元素是否属于一个集合中。
它使用多个Hash函数将一个元素映射成一个位阵列(Bit array)中的一个点,将Bit array理解为一个二进制数组,数组元素是0或1。
当一个元素加入集合时,通过N个散列函数将这个元素映射到一个Bit array中的N个点,把它们设置为1。
在这里插入图片描述
布隆过滤器的优点是:二进制数组占用空间少,插入和查询效率高效。
缺点是存在误判率,并且删除困难,因为同一个位置由于哈希冲突可能存在多个元素,删除某个元素可能删除了其它元素。

布隆过滤器的应用场景?
1、海量数据去重,比如URL去重,搜索引擎爬虫抓取网页,使用布隆过滤器可以快速判定一个URL是否已经被爬取过,避免重复爬取。
2、垃圾邮件过滤:使用布隆过滤器可以用于快速判断一个邮件地址是否是垃圾邮件发送者,对于海量的邮件地址,布隆过滤器可以提供高效的判定。
3、安全领域:在网络安全中,布隆过滤器可以用于检查一个输入值是否在黑名单中,用于快速拦截一些潜在的恶意请求。
4、避免缓存穿透:通过布隆过滤器判断是否不存在,如果不存在则直接返回。

如何代码实现布隆过滤器?
使用redit的bitmap位图结构实现。
使用redisson实现。
使用google的Guava库实现。

2.3.2 解决缓存击穿

1、使用锁(强一致性要求)
单体架构下(单进程内)可以使用同步锁控制查询数据库的代码,只允许有一个线程去查询数据库,查询得到数据库存入缓存。

synchronized(obj){
  //查询数据库
  //存入缓存
}

分布式架构下(多个进程之间)可以使用分布式锁进行控制。

// 获取分布式锁对象
RLock lock = redisson.getLock("myLock");
try {
    // 尝试加锁,最多等待100秒,加锁后自动解锁时间为30秒
    boolean isLocked = lock.tryLock(100, 30, java.util.concurrent.TimeUnit.SECONDS);
    if (isLocked) {
          //查询数据库
          //存入缓存
    } else {
        System.out.println("获取锁失败,可能有其他线程持有锁");
    }
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    // 释放锁
    lock.unlock();
    System.out.println("释放锁...");
}

2.热点数据不过期
可以由后台程序提前将热点数据加入缓存,缓存过期时间不过期,由后台程序做好缓存同步。
例如:当服务上架后将服务信息缓存到redis且永不过期,此时需要使用put注解。

3、缓存预热
分为提前预热、定时预热。
提前预热就是提前写入缓存。
定时预热是使用定时程序去更新缓存。

2.3.3 解决缓存雪崩

1、使用锁进行控制
同2.3.2

2.对同一类型信息的key设置不同的过期时间
在这里插入图片描述
3.缓存定时预热
不用等到请求到来再去查询数据库存入缓存,可以提前将数据存入缓存。使用缓存预热机制通常有专门的后台程序去将数据库的数据同步到缓存。

2.3.2 解决双写不一致

1 使用分布式式锁
既然双写操作存在不一致,我们把写缓存改为删除缓存呢?
先写数据库再删除缓存,如果删除缓存失败了缓存也就不一致了,那我们改为:先删除缓存再写数据库,如下图:
在这里插入图片描述
线程1申请分布式锁,拿到锁。此时其它线程无法获取同一把锁。
线程1写数据库,写缓存,操作完成释放锁。
线程2申请分布锁成功,写数据库,写缓存。
对双写的操作每个线程顺序执行。
对操作异常问题仍需要解决:写数据库成功写缓存失败了,数据库需要回滚,此时就需要使用分布式事务组件。
使用分布式锁解决双写一致性不仅性能低下,复杂度增加。

2 延迟双删
在这里插入图片描述
延迟多长时间呢?
延迟主数据向从数据库同步的时间间隔,如果延迟时间设置不合理也会导致数据不一致。

3 异步同步
保证最终一致性的方案有很多,比如:通过MQ、Canal、定时任务都可以实现。
Canal是一个数据同步工具,读取MySQL的binlog日志拿到更新的数据,再通过MQ发送给异步同步程序,最终由异步同步程序写到redis。此方案适用于对数据实时性有一定要求的场景。
通过Canal加MQ异步任务方式流程如下:
在这里插入图片描述
流程如下:
线程1写数据库
canal读取binlog日志,将数据变化日志写入mq
同步程序监听mq接收到数据变化的消息
同步程序解析消息内容写入redis,写入redis成功正常消费完成,消息从mq删除。

4 定时同步
专门启动一个数据同步任务定时读取数据同步到redis,此方式适用于对数据实时性要求不强更新不频繁的数据。
在这里插入图片描述
线程1写入数据库(业务数据表,变化日志表)
同步程序读取数据库(变化日志表),根据变化日志内容写入redis,同步完成删除变化日志。

3 项目缓存的具体实现

3.1 开通区域列表缓存实现

对应的需求:
在这里插入图片描述

3.1.1 缓存方案

在这里插入图片描述
下边分析第一个开通区域列表的缓存方案:
查询缓存:查询已开通区域列表,如果没有缓存则查询数据库并将查询结果进行缓存,如果存在缓存则直接返回
启用区域:删除开通区域信息缓存(再次查询将缓存新的开通区域列表)。
禁用区域:删除开通区域信息缓存,删除该区域下的其它缓存信息,包括:首页服务列表,服务类型列表,热门服务列表。
定时任务:每天凌晨缓存已开通区域列表。

3.1.2 查询缓存实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/676117.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React@16.x(17)Portals

目录 1&#xff0c;使用2&#xff0c;事件冒泡 一句话总结&#xff1a;和 Vue3 的 Teleport 一个效果。 1&#xff0c;使用 import React, { PureComponent } from "react"; import ReactDOM from "react-dom";// 返回一个 React 元素&#xff08;ReactNo…

【Go语言精进之路】构建高效Go程序:零值可用、使用复合字面值作为初值构造器

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 引言一、深入理解并利用零值提升代码质量1.1 深入Go类型零值原理1.2 零值可用性的实践与优势1.2.1 切片(Slice)的零值与动态扩展1.2.2 Map的零值与安全访问1.2.3 函数参数与零值 二、使用复合字面值作为初值构造器2.1 结构体…

十分钟快速搭建检索、排序的大模型RAG系统

以上为实现效果 RAG是目前最火的大模型应用之一&#xff0c;如何能快速实现一个不错的demo呢&#xff1f; 参考 https://github.com/LongxingTan/open-retrievalshttps://colab.research.google.com/drive/1fJC-8er-a4NRkdJkwWr4On7lGt9rAO4P?uspsharing#scrollTo2Hrfp96UY…

【算法】一文搞懂归并排序

概念 归并排序利用了分治思想&#xff0c;将待排序的数组范围层层划分&#xff0c;每次划分会得到两个大小相近的区间。当无法划分时&#xff0c;递归结束&#xff0c;自下而上进行区间合并merge操作&#xff0c;合并操作依次比较两个区间的元素&#xff0c;进而使合并后的区间…

开发和渗透偷懒利器utools

目录 1.前言 1.1 工具简介 1.2 核心特性 1.3 使用场景 1.4 安装与使用 1.4.1 下载&#xff1a; 1.4.2 安装&#xff1a; 1.4.3 配置&#xff1a; 1.4.4 插件市场&#xff1a; 2.懒狗插件介绍 基本介绍 2.1 数据模拟 2.2 随机生成虚假数据 2.3 API市场 2.4 Hoppscot…

学习小心意——简单的循坏语句

for循坏 基本语法格式 for 变量 in 序列:代码块 示例代码如下 for i in range(10):print(i)#输出结果:0 1 2 3 4 5 6 7 8 9 简单案例代码如下 利用for语句遍历序列 # 遍历字符串打印每个字母 for letter in "python":print(letter)# 遍历列表并打印每个元素 a …

Spring Boot API 编写的十个最佳实践,你知道几个?

一个好的 API 不仅能提高开发效率&#xff0c;还能确保系统的安全性和稳定性。 第一部分&#xff1a;RESTful API 设计 资源名称&#xff1a;使用名词表示资源&#xff0c;比如 /users。 HTTP 方法&#xff1a;GET、POST、PUT、DELETE 分别对应查询、创建、更新和删除操作。 …

SaaS 电商设计 (十一) 那些高并发电商系统的限流方案设计

目录 一.什么是限流二.怎么做限流呢2.1 有哪些常见的系统限流算法2.1.1 固定窗口2.1.1 滑动窗口2.1.2 令牌桶2.1.3 漏桶算法 2.2 常见的限流方式2.2.1 单机限流&集群限流2.2.2 前置限流&后置限流 2.3 实际落地是怎么做的2.3.1 流量链路2.3.2 各链路限流2.3.2.1 网关层2…

【Java面试】七、SpringMvc的执行流程、SpringBoot自动装配原理

文章目录 1、SpringMVC的执行流程1.1 视图阶段1.2 前后端分离阶段 2、SpringBoot自动配置原理3、框架常用的注解3.1 Spring的注解3.2 SpringMvc的注解3.3 SpringBoot的注解 4、面试 1、SpringMVC的执行流程 1.1 视图阶段 旧项目中&#xff0c;未前后端分离时&#xff0c;用到…

计算机视觉与模式识别实验2-2 SIFT特征提取与匹配

文章目录 &#x1f9e1;&#x1f9e1;实验流程&#x1f9e1;&#x1f9e1;SIFT算法原理总结&#xff1a;实现SIFT特征检测和匹配通过RANSAC 实现图片拼接更换其他图片再次测试效果&#xff08;依次进行SIFT特征提取、RANSAC 拼接&#xff09; &#x1f9e1;&#x1f9e1;全部代…

(CVPRW,2024)可学习的提示:遥感领域小样本语义分割

文章目录 相关资料摘要引言方法训练基础类别新类别推理 相关资料 论文&#xff1a;Learnable Prompt for Few-Shot Semantic Segmentation in Remote Sensing Domain 代码&#xff1a;https://github.com/SteveImmanuel/OEM-Few-Shot-Learnable-Prompt 摘要 小样本分割是一项…

JMeter性能测试实现与分析分享

JMeter是由著名开源软件巨头Apache组织开发的纯Java的压力测试工具&#xff0c;它即能测试动态服务&#xff08;WebService&#xff09;&#xff0c;也能测试静态资源&#xff0c;包括Servlet服务、CGI脚本等&#xff0c;还能测试动态语言服务&#xff08;PHP、Java、ASP.NET等…

外汇天眼:总是权衡利弊,投资注定失败

投资股票的人往往会频繁地评估自己的投资结果&#xff0c;尤其是在信息时代&#xff0c;手机上随时可以查看股票行情&#xff0c;导致很多人时不时地打开行情软件&#xff0c;看一看自己的股票是涨了还是跌了&#xff0c;盈利了还是亏损了。 频繁评估结果的弊端 一、引发急躁…

JVM学习-监控工具(二)

jmap&#xff1a;导出内存映像文件&内存使用情况 基本情况 jmap(JVM Memory Map)&#xff1a;一方法获取dump文件(堆转储快照文件&#xff0c;二进制文件)&#xff0c;还可以获取目标Java进程的内存相关信息&#xff0c;包括Java堆各区域的使用情况、堆中对象的统计信息、…

Golang TCP网络编程

文章目录 网络编程介绍TCP网络编程服务器监听客户端连接服务器服务端获取连接向连接中写入数据从连接中读取数据关闭连接/监听器 简易的TCP回声服务器效果展示服务端处理逻辑客户端处理逻辑 网络编程介绍 网络编程介绍 网络编程是指通过计算机网络实现程序间通信的一种编程技术…

成功解决“ModuleNotFoundError: No Module Named ‘utils’”错误的全面指南

成功解决“ModuleNotFoundError: No Module Named ‘utils’”错误的全面指南 在Python编程中&#xff0c;遇到ModuleNotFoundError: No Module Named utils这样的错误通常意味着Python解释器无法找到名为utils的模块。这可能是由于多种原因造成的&#xff0c;比如模块确实不存…

推荐一款开源Scada,数据采集必备

软件介绍 PySCADA的核心是一个基于HTML5的HMI&#xff0c;不仅确保现代性&#xff0c;还确保与各种设备的无缝集成。该框架通过提供对广泛工业协议的支持&#xff0c;进一步巩固其功能。这些包括Modbus TCP/IP、RTU、ASCII和Binary&#xff0c;让用户可以轻松地与不同的设备和系…

党历史纪念馆3d沉浸式虚拟展厅为参观者提供了一个身临其境的革命教育世界

传统的展览方式虽然能够传达一定的信息&#xff0c;但往往难以激发参观者的深度参与和共鸣。而廉政教育VR数字化展厅通过VR虚拟现实技术的运用&#xff0c;打破了传统展览的局限性&#xff0c;为参观者提供了一个身临其境的廉政世界。 在这个廉政教育VR数字化展厅中&#xff0c…

高中数学:解三角形-大题练习

例题1 解析 第一小问 根据条件等式&#xff0c;我们发现&#xff0c;每一项都含有边&#xff0c;但是&#xff0c;不是每一项都含有角 于是&#xff0c;我们要想到用正弦定理把边换为角来解答该题 第二小问 例题2 解析 第一小问 两个等式条件&#xff0c;各个项都含有边&…

代码随想录算法训练营第十三天|239. 滑动窗口最大值、 347.前 K 个高频元素

239. 滑动窗口最大值 题目链接&#xff1a;滑动窗口最大值 文档讲解&#xff1a;代码随想录 状态&#xff1a;忘了 思路1&#xff1a;使用优先队列来维护滑动窗口中的最大值&#xff0c;确保在每次滑动时能够高效地找到最大值。时间复杂度是 O(n log k)。 题解&#xff1a; cl…