我有个朋友抱怨说打排位匹配的队友太菜了,我就说我打排位觉得队友都挺行的啊?我经常躺赢。

朋友意味深长地说了句:一般隐藏分比较高的玩家,排位如果排不到实力相当的队友,就会排到一些菜狗。

嗯?我想了几秒钟感觉这小伙子不对劲,他意思是说我隐藏分低,还是说我就是那条菜狗?

我立马要求和他开黑打一把,证明我不是菜狗,他才是菜狗。

打完之后我就来发文了,虽然结果不便透露,但我对游戏的匹配机制有了一点思考。

无论是LOL的MMR机制亦或是王者荣耀的ELO机制,归根结底都是MOBA类游戏,游戏机制都是有迹可循的

所谓「隐藏分」我不知道是不是真的,毕竟匹配机制是所有竞技类游戏的核心环节,想必非常复杂,不是简单几个指标就能搞定的

但是如果把这个「隐藏分」机制简化,倒是一个值得思考的算法问题:系统如何以不同的随机概率进行匹配?

或者简单点说,如何带权重地做随机选择?

不要觉得这个很容易,如果给你一个长度为n的数组,让你从中等概率随机抽取一个元素,你肯定会做,random 一个[0, n-1]的数字出来作为索引就行了,每个元素被随机选到的概率都是1/n。

但假设每个元素都有不同的权重,权重地大小代表随机选到这个元素的概率大小,你如何写算法去随机获取元素呢?

力扣第 528 题「按权重随机选择」就是这样一个问题:

我们就来思考一下这个问题,解决按照权重随机选择元素的问题。

解法思路

这个随机算法和前缀和技巧和二分搜索技巧能扯上啥关系?且听我慢慢道来。

假设给你输入的权重数组是w = [1,3,2,1],我们想让概率符合权重,那么可以抽象一下,根据权重画出这么一条彩色的线段:

如果我在线段上面随机丢一个石子,石子落在哪个颜色上,我就选择该颜色对应的权重索引,那么每个索引被选中的概率是不是就是和权重相关联了?

所以,你再仔细看看这条彩色的线段像什么?这不就是前缀和数组嘛

那么接下来,如何模拟在线段上扔石子?

当然是随机数,比如上述前缀和数组preSum,取值范围是[1, 7],那么我生成一个在这个区间的随机数target = 5,就好像在这条线段中随机扔了一颗石子:

还有个问题,preSum中并没有 5 这个元素,我们应该选择比 5 大的最小元素,也就是 6,即preSum数组的索引 3:

如何快速寻找数组中大于等于目标值的最小元素?这里就要用到二分搜索了,确切地说是搜索左侧边界的二分搜索

到这里,这道题的核心思路就说完了,主要分几步:

1、根据权重数组w生成前缀和数组preSum。

2、生成一个取值在preSum之内的随机数,用二分搜索算法寻找大于等于这个随机数的最小元素索引。

3、最后对这个索引减一(因为前缀和数组有一位索引偏移),就可以作为权重数组的索引,即最终答案:

解法代码

上述思路应该不难理解,但是写代码的时候坑可就多了。

要知道涉及开闭区间、索引偏移和二分搜索的题目,需要你对算法的细节把控非常精确,否则会出各种难以排查的 bug。

下面来抠细节,继续前面的例子:

就比如这个preSum数组,你觉得随机数target应该在什么范围取值?闭区间[0, 7]还是左闭右开[0, 7)?

都不是,应该在闭区间[1, 7]中选择,因为前缀和数组中 0 本质上是个占位符,仔细体会一下:

所以要这样写代码:

int n = preSum.length;// target 取值范围是闭区间 [1, preSum[n - 1]]int target = rand.nextInt(preSum[n - 1]) + 1;

接下来,在preSum中寻找大于等于target的最小元素索引,应该用什么品种的二分搜索?搜索左侧边界的还是搜索右侧边界的?

实际上应该使用搜索左侧边界的二分搜索:

// 搜索左侧边界的二分搜索
int left_bound(int[] nums, int target) {if (nums.length == 0) return -1;int left = 0, right = nums.length;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {right = mid;} else if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid;}}return left;
}

前文二分搜索详解着重讲了数组中存在目标元素重复的情况,没仔细讲目标元素不存在的情况。

当目标元素target不存在数组nums中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读

1、返回的这个值是nums中大于等于target的最小元素索引。

2、返回的这个值是target应该插入在nums中的索引位置。

3、返回的这个值是nums中小于target的元素个数。

比如在有序数组nums = [2,3,5,7]中搜索target = 4,搜索左边界的二分算法会返回 2,你带入上面的说法,都是对的。

所以以上三种解读都是等价的,可以根据具体题目场景灵活运用,显然这里我们需要的是第一种。

综上,我们可以写出最终解法代码:

class Solution {// 前缀和数组private int[] preSum;private Random rand = new Random();public Solution(int[] w) {int n = w.length;// 构建前缀和数组,偏移一位留给 preSum[0]preSum = new int[n + 1];preSum[0] = 0;// preSum[i] = sum(w[0..i-1])for (int i = 1; i <= n; i++) {preSum[i] = preSum[i - 1] + w[i - 1];}}public int pickIndex() {int n = preSum.length;// 在闭区间 [1, preSum[n - 1]] 中随机选择一个数字int target = rand.nextInt(preSum[n - 1]) + 1;// 获取 target 在前缀和数组 preSum 中的索引// 搜索左侧边界的二分搜索int left = 0, right = n;while (left < right) {int mid = left + (right - left) / 2;if (preSum[mid] < target) {left = mid + 1;} else {right = mid;}}// preSum 的索引偏移了一位,还原为权重数组 w 的索引return left - 1;}
}

有了之前的铺垫,相信你能够完全理解上述代码,这道随机权重的题目就解决了。

你打英雄联盟or王者荣耀为什么老是匹配到怨种队友,进来看相关推荐

  1. 官宣!英雄联盟、王者荣耀、街霸……这些电子竞技入选杭州亚运会

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 2021年11月5日,杭州亚运会官方微博发布杭州2022年第19届亚 ...

  2. 从零开发英雄联盟、王者荣耀电竞比分预测系统

    从零开发英雄联盟.王者荣耀电竞比分预测系统 快速开发一款电竞比分预测系统 想要快速熟悉电竞比分预测的逻辑,你总是需要付出时间和精力的,对于程序员的成长,最好的方法就是从一个项目入手,下面让我来教你手把 ...

  3. 程序员大佬Java开发大型3D游戏,英雄联盟、王者荣耀算什么!

    落樱(LuoYing)是一个用于简化3D角色扮演游戏开发的游戏框架,该项目基于Java及JME3(JMonkeyEngine)进行开发,兼容JME,创建的游戏可以跨多个平台发布(Window\Linu ...

  4. 英雄联盟祖安服务器位置,英雄联盟《王者峡谷》全民线上海选赛报名开启

    原标题:英雄联盟<王者峡谷>全民线上海选赛报名开启 2016<王者峡谷>即将战火重燃.本年度<王者峡谷>报名通道将于6月8日开启.比赛将从7月持续到8月31日.王者 ...

  5. 王者荣耀显示服务器爆满进不去,王者荣耀榜一二秀恩爱,服务器爆满进不去,榜四:他俩不是人...

    原标题:王者荣耀榜一二秀恩爱,服务器爆满进不去,榜四:他俩不是人 圣杯张飞一声吼,王者峡谷抖三抖,游戏日报虾米酱又与大家见面啦.最近王者荣耀出了件稀奇事,安卓微信某无人问津的小区竟被挤爆,火爆程度相当 ...

  6. java给英雄加血_王者荣耀:能给队友加血的五大英雄,女娲加血方法只有老手才知道...

    王者荣耀:能给队友加血的五大英雄,女娲加血方法只有老手才知道 第一位:女娲,女娲其实并没有给队友回血的技能,但是只要是经常玩女娲的小伙伴都知道,女娲的技能被动可以帮你回血,技能被动可以让你在击打指定英 ...

  7. 软件英雄技能测试,王者荣耀:官方评级与实际难度不符的英雄,工具人有这么难?...

    原标题:王者荣耀:官方评级与实际难度不符的英雄,工具人有这么难? 王者荣耀官方对不同的英雄难度有不同的划分,他们根据自己的数据和测试把所有英雄按1-10分成不同的难度.但是虽然是官方自己定的难度但是还 ...

  8. 我昏迷了!被王者荣耀的AI吊打后,队友想了一个损招……

    还记得2年前,王者荣耀的人机模式,还是简单的"送分模式",青铜的我也能轻松7杀超神. 但是不知道从什么时候开始,机器人再也不是蠢萌的机器人了,全都变成了"没有感情的杀手& ...

  9. 新服务器怎么开无线火力,王者荣耀无限火力怎么创建 无限火力入口在哪里进...

    王者荣耀无限火力怎么创建?王者荣耀无限火力怎么进入?无限火力模式在哪里可以玩?相信很多玩家都听说即将开启"无限火力"模式的一些话题.话不多说,下面,就随琵琶网小编来了解一下吧! 王 ...

最新文章

  1. java consumer_Java 8 Consumer接口
  2. ByteBuffer详解
  3. Oracle 用数据泵导入导出数据
  4. Anaconda中Jupyter notebook打开后闪退问题解决方法
  5. JavaSE(九)——正则表达式、Date类、集合、泛型
  6. 【SpringBoot MQ 系列】RabbitListener 消费基本使用姿势介绍
  7. mysql 集群怎么卸载节点_Greenplum移除节点
  8. php中改变函数路由,通过PHP重启路由器以更换IP(原创)
  9. CPU上跑深度学习模型,FPS也可以达100帧
  10. linux 减小根分区大小_减小linux下根分区
  11. TOP 10 开源的推荐系统简介
  12. php mvc 实现,php mvc的简单实现
  13. android网页自动输入,android浏览器自动填表
  14. 《穿越计算机的迷雾》第一版说明
  15. 5.0安装没有costom mysql_MySql5.0安装图解s
  16. python爬虫入门(5)----- 阿里巴巴供应商爬虫
  17. 一些植物查询的网站链接
  18. 什么是CPS?数字孪生技术在工业4.0该如何应用?ThingJS
  19. 淘宝API item_search_jupage - 天天特价
  20. java常用类库——util包

热门文章

  1. 齐鲁理工学院计算机专业在哪个校区,齐鲁理工学院有几个校区,哪个校区最好及各校区介绍...
  2. 专访阿里金融云徐敏:为普惠金融地提供技术原力
  3. 2022学年第一学期郑州大学ACM招新赛选拔赛
  4. 怎么查阅参考文献资料?
  5. 数据库 多表 查询练习题
  6. python目标检测给图画框,bbox画到图上并保存
  7. S5pv210 出现一个离奇wince6.0 activesync 软件连接问题
  8. 主线程 如何控制 子线程
  9. Ubuntu VNC 如何调整分辨率
  10. 2021年南京大学842考研-软件工程部分代码设计题