简单聊聊微信红包及其算法

昨天有个小伙伴在微信群里发一篇文章《如何实现抢红包算法》,本着学习的精神(上班太闲) 打开了看看。

文章主要是介绍了两种方法

1.二倍均值法

剩余红包金额为M,剩余人生为N,那么有如下的公式:

每次抢到的金额 = 随机区间 (0, M/N *2)

举个例子:

假设有10个人,红包金额为10元,

第1个人抢到的金额范围为 (0, 10/10 * 2),平均为1 元。

第2个人抢到的金额范围为 (0, 9/9 * 2),平均为1 元。

...

第10个人抢到的金额范围为 (0, 1/1 * 2),平均为1 元。

代码如下:

import random
from __future__ import division

def average(amount, nums):
    remain_num = nums
    for num in range(nums):
        if remain_num == 1:
            value = amount
        else:
            value = round(random.uniform(0.01, amount/remain_num * 2), 2)
        amount -= value
        remain_num -= 1
        print('第{}个人抢到{}元红包,剩余红包{}元'.format(num+1, value, amount))
>>> average(10, 10)
第1个人抢到0.58元红包,剩余红包9.42元
第2个人抢到1.62元红包,剩余红包7.8元
第3个人抢到0.55元红包,剩余红包7.25元
第4个人抢到0.86元红包,剩余红包6.39元
第5个人抢到1.7元红包,剩余红包4.69元
第6个人抢到1.51元红包,剩余红包3.18元
第7个人抢到0.32元红包,剩余红包2.86元
第8个人抢到1.06元红包,剩余红包1.8元
第9个人抢到1.43元红包,剩余红包0.37元
第10个人抢到0.37元红包,剩余红包0.0元
>>> average(10, 10)
第1个人抢到0.35元红包,剩余红包9.65元
第2个人抢到0.35元红包,剩余红包9.3元
第3个人抢到1.58元红包,剩余红包7.72元
第4个人抢到0.17元红包,剩余红包7.55元
第5个人抢到2.48元红包,剩余红包5.07元
第6个人抢到0.79元红包,剩余红包4.28元
第7个人抢到0.99元红包,剩余红包3.29元
第8个人抢到0.79元红包,剩余红包2.5元
第9个人抢到0.33元红包,剩余红包2.17元
第10个人抢到2.17元红包,剩余红包0.0元

二、线性分割法

我们可以把红包总金额想象成一条很长的线段,而每个人抢到的金额,则是这条主线段所拆分出的若干子线段。

简单聊聊微信红包及其算法_第1张图片

如何确定每一条子线段的长度呢?由“切割点”来决定。当N个人一起抢红包的时候,就需要确定N-1个切割点。

代码如下:

import random


def line_cut(total, number):
    """
    生成切断点 (list)
    :param total:  总数
    :param number:  人数
    :return:
    """
    cut_num = number - 1
    random_list = []
    for i in range(cut_num):
        while True:
            random_num = random.randint(1, total)
            if random_num not in random_list:
                random_list.append(random_num)
                break
    return sorted(random_list)

def amount(total, random_list):
    """
    根据切割点分配金额
    :param total:
    :param random_list:
    :return:
    """
    test_total = 0
    for i in range(len(random_list)+1):
        try:
            num = random_list[0] if i == 0 else random_list[i+1] - random_list[i]
        except:
            try:
                num = total - random_list[i]
            except:
                num = total - test_total
        test_total += num
        print('第{}个人分配金额{}, 剩余金额{}'.format(i+1, num, total-test_total))

if __name__ == '__main__':
    total, number = 100, 10
    random_list = line_cut(total, number)
    amount(total, random_list)

了解了基本的红包算法,好奇心使我打开google查看下微信红包到底使用了哪种方式。简单聊聊微信红包及其算法_第2张图片简单聊聊微信红包及其算法_第3张图片

有点不相信啊。我要开始我的测试,首先进行小额测试,我发4个红包,金额是0.05,只有第3,4人才有可能领到0.02,

下面是我的验证

简单聊聊微信红包及其算法_第4张图片简单聊聊微信红包及其算法_第5张图片

还有很多图就不放了,都是最后一个人是0.02。心有点动摇了啊,,再使用另一个维度测试,我发1元10个包,

那第一个人永远不超过0.2元,下面是我的测试:

简单聊聊微信红包及其算法_第6张图片简单聊聊微信红包及其算法_第7张图片

现在看来是微信采用的是二倍均值法无疑了。

那么问题来了,我们应该先抢还是后抢的?

这得看你是否想要大额,因为前面抢的是比较平均的。不可能出现大额。

想要大额,后面抢,但是是有风险抢到小额,就是波动较大。(还有特么可能没有红包了)

你可能感兴趣的:(简单聊聊微信红包及其算法)