这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
一、本堂课重点内容:
- 代码实践 - 分红包
二、详细知识点介绍:
1. 代码实践 - 分红包
要求:每个红包至少有0.01元,每个红包的金额与红包数量的乘积为总金额,每个红包内的金额是精度为小数点后2位的随机数。
假设总金额为0.1元,要分为10个红包,为了保证每个红包至少有0.01元,应该分为10个0.01元的红包。
假设总金额为0.09元,要分为10个红包,无法保证每个红包至少有0.01元,则无法分红包。
切西瓜法:
思路:不断将最大的一份进行不均等的随机二分,直到分出的数量等于所需数量。
在generate方法中,首先用Math.max取出数组中最大的一个作为cake,再用indexOf获取它的下标,然后随机获取不大于cake的一部分作为part,cake减去part的部分作为rest,然后在原数组中用splice将原来的cake替换为part和rest。循环多次直到数组项等于需要的项数,即完成分红包。
获取part时,用Math.random获取随机数,乘cake的1/2,再用Math.floor向下取整,由于取值范围为0~cake/2,向下取整可能为0,无法切分,所以结果要+1。
缺点:时间复杂度为O(n),效率不高,且因为每次都切分最大的一份,红包的金额较为均匀。
抽牌法:
思路:把红包总额100元(即10000分)看成一个0~9999的数列,分成10个红包就相当于在数列中插入9个分隔符,两个分隔符之间的金额作为一个红包的金额。
首先使用Array(amount-1).fill(0).map((_,1) => i + 1)生成长度为amount(总金额)的随机数列,然后通过生成器draw在数列中随机抽取count-1(红包数量)个数,将这些数存放到result数组中。将result进行排序后,将amount添加到数组最后,再将result中的每个数转化为当前数减去上一个数的所得值,因此result就作为最终每个红包的金额。
缺点:空间复杂度高。
三、课后个人总结:
在实现分红包的功能时,可以使用切西瓜法,不断将大的部分随机二分,但是这样会导致红包金额较均匀,缺乏随机性。
因此也可以采用抽牌法,选择其中的一些值作为分隔符,将这之间的金额作为单个红包的金额,提高了金额随机性。