产品经理 : 老司机,你那边开发个领取红包的版块。我给一定的金额总数,红包个数,最高发放金额,以及最低发放金额,你要随机生成固定个数的红包,红包总额不能超过金额总数。
老司机 : 你(笔者),去实现这个算法,把生成的红包全部丢到数据库里面。

好吧,就这样,这个需求就让我实现了。其实业务看起来说的很复杂,其实就是例如我有1000元,我想发放100个红包,最高不能超过20块,最低不能低于1块。
当时我也不太清楚这个算法要怎么写,上网搜索了下,找到一种比较合理的算法,是用微积分去实现(我会把代码贴出来)的。算法原理如下


(原文地址:http://blog.csdn.net/cleverco...
我刚开始觉得这个算法确实很不错,但仔细看了下里面的源码后觉得会比较耗性能,而且回头一看公司的需求,其实也就个红包生成(在项目经理没要求需要正态分布的情况下),没必要把复杂简单的东西弄复杂了。所以我思来想去想了一个晚上,终于写出了个比较合理的算法。

/*
 * 获取随机红包
 * min<k<max
 * min(n-1) <= money - k <= (n-1)max
 * k <= money-(n-1)min
 * k >= money-(n-1)max
 */
function getRedPackage($money, $num, $min, $max)
{
    $data = array();
    if ($min * $num > $money) {
        return array();
    }
    if($max*$num < $money){
        return array();
    }
    while ($num >= 1) {
        $num--;
        $kmix = max($min, $money - $num * $max);
        $kmax = min($max, $money - $num * $min);
        $kAvg = $money / ($num + 1);
        //获取最大值和最小值的距离之间的最小值
        $kDis = min($kAvg - $kmix, $kmax - $kAvg);
        //获取0到1之间的随机数与距离最小值相乘得出浮动区间,这使得浮动区间不会超出范围
        $r = ((float)(rand(1, 10000) / 10000) - 0.5) * $kDis * 2;
        $k = round($kAvg + $r);
        $money -= $k;
        $data[] = $k;
    }
    return $data;
}

这个算法的原理其实就是根据剩余不断变化的平均值去加减随机数做到不超过总额,但红包的分布就没那么平均。


差不多有三个月没写文章了,主要是这三个月一直在学习新的东西,相关php的工具,workman,kafka,以及golang。学的东西很杂,但也做出了效果,每天都在公司躲到11点后才回家。笔者也建议phper新人们,不要单纯限制在php语言里面,以及去讨论php是否是最好的编程语言之类的。毕竟能解决问题的武器就是好武器,一个工程师被公司聘请来就是解决问题的(大声喊出来,我们不是码农)。

03-05 18:26