某马点评——day04

达人探店

发布探店笔记

 改一下,图片保存路径就可以直接运行测试了。

查看探店笔记

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {@Resourceprivate IUserService userService;@Overridepublic Result queryBlogById(Long id) {//1.查询blogBlog blog = getById(id);if(blog==null){return Result.fail("笔记不存在");}//2.查询blog有关用户queryBlogUser(blog);return Result.ok(blog);}private void queryBlogUser(Blog blog) {Long userId = blog.getUserId();User user = userService.getById(userId);blog.setName(user.getNickName());blog.setIcon(user.getIcon());}@Overridepublic Result queryHotBlog(Integer current) {// 根据用户查询Page<Blog> page = query().orderByDesc("liked").page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));// 获取当前页数据List<Blog> records = page.getRecords();// 查询用户records.forEach(this::queryBlogUser);return Result.ok(records);}
}

点赞

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {@Resourceprivate IUserService userService;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryBlogById(Long id) {//1.查询blogBlog blog = getById(id);if(blog==null){return Result.fail("笔记不存在");}//2.查询blog有关用户queryBlogUser(blog);//3.查询blog是否被点赞isBlogLiked(blog);return Result.ok(blog);}private void isBlogLiked(Blog blog) {//1.判获取登录用户Long userId = UserHolder.getUser().getId();//2.判断当前登录用户是否已经点赞String key=BLOG_LIKED_KEY+blog.getId();Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());blog.setIsLike(BooleanUtil.isTrue(isMember));}private void queryBlogUser(Blog blog) {Long userId = blog.getUserId();User user = userService.getById(userId);blog.setName(user.getNickName());blog.setIcon(user.getIcon());}@Overridepublic Result queryHotBlog(Integer current) {// 根据用户查询Page<Blog> page = query().orderByDesc("liked").page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));// 获取当前页数据List<Blog> records = page.getRecords();// 查询用户records.forEach(blog->{this.queryBlogUser(blog);this.isBlogLiked(blog);});return Result.ok(records);}@Overridepublic Result likeBlog(Long id) {//1.判获取登录用户Long userId = UserHolder.getUser().getId();//2.判断当前登录用户是否已经点赞String key=BLOG_LIKED_KEY+id;Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());if(BooleanUtil.isFalse(isMember)) {//3.如果未点赞//3.1数据库点赞数+1boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();//3.2保存用户到Redis的set集合if(isSuccess){stringRedisTemplate.opsForSet().add(key,userId.toString());}}else {//4.如果已点赞,取消点赞//4.1数据库点赞数-1boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();//4.2把用户从redis的set集合删除stringRedisTemplate.opsForSet().remove(key,userId.toString());}return Result.ok();}
}

点赞排行榜

 为了将最早点赞的人摆在最前面,需要按照时间先后存储分数,这里使用zset存储时间戳作为zset的score作为排序的依据。

然后针对mysql的排序会乱序的问题需要自定义排序规则,将数据按照指定顺序展示.

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {@Resourceprivate IUserService userService;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryBlogById(Long id) {//1.查询blogBlog blog = getById(id);if(blog==null){return Result.fail("笔记不存在");}//2.查询blog有关用户queryBlogUser(blog);//3.查询blog是否被点赞isBlogLiked(blog);return Result.ok(blog);}private void isBlogLiked(Blog blog) {//1.判获取登录用户UserDTO user = UserHolder.getUser();if(user==null){//用户未登录,无需查询是否点赞return;}Long userId = user.getId();//2.判断当前登录用户是否已经点赞String key=BLOG_LIKED_KEY+blog.getId();Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());blog.setIsLike(score!=null);}private void queryBlogUser(Blog blog) {Long userId = blog.getUserId();User user = userService.getById(userId);blog.setName(user.getNickName());blog.setIcon(user.getIcon());}@Overridepublic Result queryHotBlog(Integer current) {// 根据用户查询Page<Blog> page = query().orderByDesc("liked").page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));// 获取当前页数据List<Blog> records = page.getRecords();// 查询用户records.forEach(blog->{this.queryBlogUser(blog);this.isBlogLiked(blog);});return Result.ok(records);}@Overridepublic Result likeBlog(Long id) {//1.判获取登录用户Long userId = UserHolder.getUser().getId();//2.判断当前登录用户是否已经点赞String key=BLOG_LIKED_KEY+id;Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());if(score==null) {//3.如果未点赞//3.1数据库点赞数+1boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();//3.2保存用户到Redis的set集合 zadd key value scoreif(isSuccess){stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());}}else {//4.如果已点赞,取消点赞//4.1数据库点赞数-1boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();//4.2把用户从redis的set集合删除stringRedisTemplate.opsForZSet().remove(key,userId.toString());}return Result.ok();}@Overridepublic Result queryBlogLikes(Long id) {//1.查询top5的点赞用户 zrange key 0 4String key=BLOG_LIKED_KEY+id;Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);if(top5==null||top5.isEmpty()){return Result.ok(Collections.emptyList());}//2.解析出用户idList<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());//将id拼成字符串String idStr = StrUtil.join(",", ids);//3.根绝用户id查询用户 必须自定义排序规则进行查询,否则原本是有序的数据查完之后就变成无序的了List<UserDTO> userDTOS = userService.query().in("id",ids).last("ORDER BY FIELD(id,"+idStr+")").list().stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());//4.返回return Result.ok(userDTOS);}
}

好友关注

关注和取关

一个接口实现关注和取关

@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {/*** 关注取关功能* @param followUserId* @param isFollow* @return*/@Overridepublic Result follow(Long followUserId, Boolean isFollow) {//1.获取登录用户Long userId = UserHolder.getUser().getId();//1.判断到底是关注还是取关if (isFollow) {//2.关注,新增数据Follow follow = new Follow();follow.setUserId(userId);follow.setFollowUserId(followUserId);save(follow);}else{//3.取关,删除 delete from tb_follow where userId = ? and follow_user_id = ?remove(new QueryWrapper<Follow>().eq("user_id",userId).eq("follow_user_id",followUserId));}return Result.ok();}@Overridepublic Result isFollow(Long followUserId) {//1.获取登录用户Long userId = UserHolder.getUser().getId();//2.查询是否关注 select count(*)  from tb_follow where userId = ? and follow_user_id = ?Integer count = query().eq("user_id", userId).eq("follow_user_id", followUserId).count();//3.判断return Result.ok(count>0);}
}

共同关注

这两个接口直接使用资料里的代码片段

// UserController 根据id查询用户@GetMapping("/{id}")
public Result queryUserById(@PathVariable("id") Long userId){// 查询详情User user = userService.getById(userId);if (user == null) {return Result.ok();}UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);// 返回return Result.ok(userDTO);
}// BlogController
@GetMapping("/of/user")
public Result queryBlogByUserId(@RequestParam(value = "current", defaultValue = "1") Integer current,@RequestParam("id") Long id) {// 根据用户查询Page<Blog> page = blogService.query().eq("user_id", id).page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));// 获取当前页数据List<Blog> records = page.getRecords();return Result.ok(records);
}

 为了能用redis的set集合取交集求得共同关注的好友,这里要将一个用户关注的所有人都存储到redis里的set集合,,取关了从set集合里删除。

代码实现

    @Overridepublic Result followCommons(Long id) {//1.获取当前用户Long userId = UserHolder.getUser().getId();String key="follows:"+userId;//2.求交集String key2="follows:"+id;Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key, key2);if(intersect==null||intersect.isEmpty()){//无交集return Result.ok(Collections.emptyList());}//3.解析id集合List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());//4.查询用户List<UserDTO> users = userService.listByIds(ids).stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());return Result.ok(users);}

关注推送

有点像观察者模式,观察者给监听者集体发送消息。

 feed流实现方案分析 

拉模式下会将用户关注的人的消息全都拉取到收件箱里面按照时间进行排序。 这个模式下,消息只会在作者的发件箱持久保存一份,用户的收件箱每次打开都会去拉取一份新的,用完就删。每次都读取一堆,性能消耗大。

 推模式下会将消息发送到用户的收件箱持久化保存。但是这个模式下一个消息会写n份,内存占用高。

普通v直接用推模式,大v的活跃粉丝用推模式,普通粉丝数量多用拉模式。 

 基于推模式实现关注推送功能

这里选择推送blog的id到用户的收件箱,用户要看时再现查。

这里使用Redis的Zset进行保存,基于时间戳进行排序,要进行分页查询时利用角标0~n。

这里传统分页好像是有个问题,会出现相同商品重复出现的情况。然后利用滚动分页就不会有这种情况,但是这样话新数据又去哪里了? 

 

使用sortedSet实现的时候,每次分页记住时间戳最小的那个,下次查就从更小的开始,就不会出现数据重复了。

推送代码实现

改造新增blog的代码,在新增成功的时候获取所有粉丝id进行blog推送。

    @Overridepublic Result saveBlog(Blog blog) {// 1.获取登录用户UserDTO user = UserHolder.getUser();blog.setUserId(user.getId());// 2.保存探店博文boolean isSucess = save(blog);if(!isSucess){return Result.fail("新增笔记失败");}//3.查询笔记作者的所有粉丝 select * from tb_follow where follow_user_id=?List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();//4.推送笔记id给所有粉丝for(Follow follow:follows){//4.1获取粉丝idLong userId = follow.getUserId();//4.2推送String key=FEED_KEY+userId;stringRedisTemplate.opsForZSet().add(key,blog.getId().toString(),System.currentTimeMillis());}// 3.返回idreturn Result.ok(blog.getId());}
滚动分页查询收件箱思路

使用的是zrange,不能按照角标查询,要按照score进行查询.

所以这里使用按照分数查询的命令. 但是这里也会存在问题,如果存在两个相同score的话,可能也会出现重复,因为命令是按照小于等于。

滚动分页查询实现 

这个代码好像还是有点问题,这里查询了blog有关用户和是否点赞却没有用上

@Data
public class ScrollResult {private List<?> list;private Long minTime;private Integer offset;
}
    @GetMapping("/of/follow")public Result queryBlogOfFollow(@RequestParam("lastId") Long max, @RequestParam(value = "offset",defaultValue = "0") Integer offset){return blogService.queryBlogOfFollow(max,offset);}
    @Overridepublic Result queryBlogOfFollow(Long max, Integer offset) {//1.获取当前用户Long userId = UserHolder.getUser().getId();//2.查询收件箱 ZREVRANGBYSCORE key MAX MIN WITHSCORES LIMIT offset countString key=FEED_KEY+userId;Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 2);//3.非空判断if(typedTuples==null||typedTuples.isEmpty()){return Result.ok();}//4.解析数据: blogId ,mintime(时间戳),offsetList<Long> ids=new ArrayList<>(typedTuples.size());long minTime=0;int os=1;for (ZSetOperations.TypedTuple<String> tuple : typedTuples) { ////4.1获取idids.add(Long.valueOf(tuple.getValue()));//4.2获取分数(时间戳)long time=tuple.getScore().longValue();if(time==minTime){os++;}else{minTime=time;os=1;}}//5.根据id查询blog 基于in语句查询会打乱顺序String idStr = StrUtil.join(",", ids);List<Blog> blogs =query().in("id",ids).last("ORDER BY FIELD(id,"+idStr+")").list();for (Blog blog : blogs) {//5.1.查询blog有关的用户queryBlogUser(blog);//5.2.查询blog是否被点赞isBlogLiked(blog);}//6.封装并返回ScrollResult scrollResult = new ScrollResult();scrollResult.setList(blogs);scrollResult.setMinTime(minTime);scrollResult.setOffset(os);return Result.ok(scrollResult);}

附近商铺

GEO数据结构的基本用法

 

导入店铺数据到GEO

写一个数据导入的测试类

 

    @Testvoid loadShopDate(){//1.查询店铺信息List<Shop> list = shopService.list();//2.把店铺分组,按照typeId分组,typeId一致的放到一个集合Map<Long,List<Shop>>  map=list.stream().collect(Collectors.groupingBy(Shop::getTypeId));//3.分批完成写入Redisfor (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {//3.1获取类型idLong typeId = entry.getKey();String key= SHOP_GEO_KEY+typeId;//3.2获取同类型的店铺的集合List<Shop> value = entry.getValue();List<RedisGeoCommands.GeoLocation<String>> locations=new ArrayList<>();//3.3写入redis geoadd key 经度 维度 memberfor (Shop shop : value) {//写入一条数据//stringRedisTemplate.opsForGeo().add(key,new Point(shop.getX(),shop.getY()),shop.getId().toString());locations.add(new RedisGeoCommands.GeoLocation<>(shop.getId().toString(),new Point(shop.getX(),shop.getY())));}//一次写入多条数据stringRedisTemplate.opsForGeo().add(key,locations);}}

实现附近商户功能

用户签到

BitMap功能演示 

这个表格里的每一行数据就是用户的一条签到记录,现在使用二进制压缩来存储.

实现签到功能

 代码实现

    @Overridepublic Result sign() {//1.获取当前登录用户Long userId = UserHolder.getUser().getId();//2.获取日期LocalDateTime now = LocalDateTime.now();//3.拼接keyString keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));String key=USER_SIGN_KEY+userId+keySuffix;//4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();//5.写入Redis SETBIT key offset 1stringRedisTemplate.opsForValue().setBit(key, dayOfMonth-1,true);return Result.ok();}

统计连续签到

代码实现

@Overridepublic Result signCount() {//1.获取当前登录用户Long userId = UserHolder.getUser().getId();//2.获取日期LocalDateTime now = LocalDateTime.now();//3.拼接keyString keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));String key=USER_SIGN_KEY+userId+keySuffix;//4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();//5.获取本月截止今天为止的所有的签到记录,要返回的是一个十进制的数字 BITFIELD sign:8:202312 GET u14 0List<Long> result = stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0) //今天多少号就多少个bit位);if(result==null||result.isEmpty()){//没有任何签到结果return Result.ok(0);}Long num=result.get(0);if(num==null||num==0){return Result.ok(0);}//6.循环遍历int count=0;while(true){//6.1让这个数字与1做与运算,得到数字的最后一个bit位//判断这个bit位是否为0if ((num&1)==0) {//如果为0,说明未签到,结束break;}else{//如果不为0,说明已签到,计数器+1count++;}//把数字右移一位,抛弃最后一个bit位,继续下一个bit位num>>>=1;}return Result.ok(count);}

UV统计

HyperLogLog的用法

 

测试百万数据的统计

    @Testvoid testHyperLogLog(){//准备数组,装用户数据String[] users = new String[1000];//数据角标记int index=0;for(int i=1;i<=1000000;i++){//赋值users[index++]="user_"+i;//每1000条发送一次if(i%1000==0){index=0;stringRedisTemplate.opsForHyperLogLog().add("hl2",users);}}//统计数量Long hl2 = stringRedisTemplate.opsForHyperLogLog().size("hl2");System.out.println(hl2);}

这个测试方法一直运行失败,我真的吐了.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCL学习笔记(二)手动编译开发库(win10+vs2019)

前言 有时需求比较特别&#xff0c;可能需要重新编译opencl的sdk库。本文档简单记录下win10下&#xff0c;使用vs2019编译的过程&#xff0c;有需要的小伙伴可以参考下 一、获取源码 项目地址&#xff1a;GitHub - KhronosGroup/OpenCL-SDK: OpenCL SDK 可以直接使用git命令…

一篇文章了解指针变量

字符指针变量 在指针的类型中我们知道有一种指针叫做字符指针 它的使用情况如下&#xff1a; #include<stdio.h> int main() {char pa w;char*p1&pa;*p1 a;printf("%c\n", *p1);return 0; } 在这段代码当中&#xff0c;我们将‘w’字符的地址传到了p…

vue3 自己写一个月的日历

效果图 代码 <template><div class"monthPage"><div class"calendar" v-loading"loading"><!-- 星期 --><div class"weekBox"><div v-for"(item, index) in dayArr" :key"index&q…

2.修改列名与列的数据类型

修改字段名与字段数据类型 1.修改字段名 有时&#xff0c;在我们建好一张表后会突然发现&#xff0c;哎呀&#xff01;字段名貌似写错了&#xff01;怎么办&#xff1f;要删了表再重新建一个新表吗&#xff1f;还是要删了这个字段再新建一个新的字段&#xff1f; 都不用&…

AIGC专题报告:生成式人工智能人人可用的新时代

今天分享的AIGC系列深度研究报告&#xff1a;《AIGC专题报告&#xff1a;生成式人工智能人人可用的新时代》。 &#xff08;报告出品方&#xff1a;埃森哲&#xff09; 报告共计&#xff1a;21页 人工智能发展迎来新拐点 ChatGPT 正在唤醒全球对人工智能&#xff08;AI&…

在pom.xml中添加maven依赖,但是类里面import导入的时候报错

问题&#xff1a; Error:(27, 8) java: 类TestKuDo是公共的, 应在名为 TestKuDo.java 的文件中声明 Error:(7, 23) java: 程序包org.apache.kudu不存在 Error:(8, 23) java: 程序包org.apache.kudu不存在 Error:(9, 23) java: 程序包org.apache.kudu不存在 Error:(10, 30) jav…

【Java探索之旅】我与Java的初相识(一):Java的特性与优点及其发展史

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 一. Java语言概述与优势1.1 Java的概述1.2 Java语言的优势 二. Java领域与发展史2.1 Java的使用领域2.…

面试多线程八股文十问十答第二期

面试多线程八股文十问十答第二期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.进程和线程的区别 概念不同&#xff1a;进程是操作系统中的一个独立执行单元&a…

目标检测mAP计算以及coco评价标准

这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 讲一下目标检测中的一些常见的指标 在我们使用目标检测网络训练时 最后在验证集上会得到一个coco的评价列表 就像我们图中给的这一系列参数列表一样 我们再进一步引入两个概念 第一个叫做precisi…

P1 Qt的认识及环境配置

目录 前言 01 下载Qt Creator windows下载安装包拷贝到Linux Linux直接下载 02 Linux 安装Qt 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类…

地址栏不安全提示

在使用浏览器时访问网站的时候&#xff0c;我们可能会遇到地址栏提示不安全的情况。这种情况通常都是是由于未安装有效SSL证书或者网站SSL证书过期等原因导致的。本文将介绍如何处理地址栏提示不安全的问题&#xff0c;以确保我们的上网安全。 1&#xff0c;缺少SSL证书&#x…

基于单片机音乐盒仿真仿真系统设计

**单片机设计介绍&#xff0c;基于单片机音乐盒仿真仿真系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的音乐盒仿真仿真系统是一种基于嵌入式系统技术的设计方案&#xff0c;用于模拟传统的音乐盒功能。它通…

002 self-attention自注意力

目录 一、环境 二、self-attention原理 三、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17torch 1.13.1cu117torchvision 0.14.1cu117 二、self-attention原理 自注意力&#xff08;Self-Attention&#xff09;操作是基于 Transformer 的机器翻…

华清远见嵌入式学习——QT——作业2

作业要求&#xff1a; 代码运行效果图&#xff1a; 登录失败 和 最小化 和 取消登录 登录成功 和 X号退出 代码&#xff1a; ①&#xff1a;头文件 #ifndef LOGIN_H #define LOGIN_H#include <QMainWindow> #include <QLineEdit> //行编辑器类 #include…

Java Spring + SpringMVC + MyBatis(SSM)期末作业项目

本系统是一个图书管理系统&#xff0c;比较适合当作期末作业主要技术栈如下&#xff1a; - 数据库&#xff1a;MySQL - 开发工具&#xff1a;IDEA - 数据连接池&#xff1a;Druid - Web容器&#xff1a;Apache Tomcat - 项目管理工具&#xff1a;Maven - 版本控制工具&#xf…

探索人工智能领域——每日20个名词详解【day12】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

进程、线程、线程池状态

线程几种状态和状态转换 进程主要写明三种基本状态&#xff1a; 线程池的几种状态&#xff1a;

STM32的BKP与RTC简介

芯片的供电引脚 引脚表橙色的是芯片的供电引脚&#xff0c;其中VSS/VDD是芯片内部数字部分的供电&#xff0c;VSSA/VDDA是芯片内部模拟部分的供电&#xff0c;这4组以VDD开头的供电都是系统的主电源&#xff0c;正常使用时&#xff0c;全部都要接3.3V的电源上&#xff0c;VBAT是…

Leetcode2477. 到达首都的最少油耗

Every day a Leetcode 题目来源&#xff1a;2477. 到达首都的最少油耗 解法1&#xff1a;贪心 深度优先搜索 题目等价于给出了一棵以节点 0 为根结点的树&#xff0c;并且初始树上的每一个节点上都有一个人&#xff0c;现在所有人都需要通过「车子」向结点 0 移动。 对于…

从阻抗匹配看拥塞控制

先来理解阻抗匹配&#xff0c;但我不按传统方式解释&#xff0c;因为传统方案你要先理解如何定义阻抗&#xff0c;然后再学习什么是输入阻抗和输出阻抗&#xff0c;最后再看如何让它们匹配&#xff0c;而让它们匹配的目标仅仅是信号不反射&#xff0c;以最大能效被负载接收。 …