一个简单的上下界红包随机算法实现

概述

  • 在公司题库看到了这个,有点好奇微信的红包算法是怎么实现的,知乎看到了这个答案:微信红包的随机算法是怎样实现的? - 陈鹏的回答 - 知乎
  • 总结下核心的几点:
    • 内存实时计算模型,这个和电商体系下很多离线计算的红包不同,故在点击红包页面和领取红包详情页其实是两个状态,从用户动线角度手慢则无其实也合理
    • 判定是否还有红包可领取时类似商品库存一样有个分布式锁的判定,当领取红包后CAS模式写库,然后再跟财付通对账
    • 算法本身也并不是绝对均等,做到了大致均等

实现

PS:这里我们假设红包是有上下界的,即每个人拿到的红包有最大和最小值限制,那么当每次计算时需要check仍未分配的红包可能的最大值和最小值,详见代码:

public class WxRandomHongbao {

    //总人数和总红包数
    private static final double TOTAL_AMOUNT = 1000.0;
    private static final int TOTAL_USERS = 6;

    private static double getRandomVal(double min, double max) {
        Random random = new Random();
        return random.nextDouble() * (max - min) + min;
    }

    /**
     * 红包分配算法
     *
     * @param remainUser  剩余人数
     * @param remainMoney 剩余红包
     * @param minMoney    最小值
     * @param maxMoney    最大值
     * @return
     */
    public static double getRandomMoney(int remainUser, double remainMoney,
                                        double minMoney, double maxMoney) {
        if (remainUser == 1) {
            return (double)Math.round(remainMoney * 100) / 100;
        }
        //计算随机红包上下界限制
        double minBound = Math.max(remainMoney - (remainUser - 1) * maxMoney, minMoney);
        double maxBound = Math.min(remainMoney - (remainUser - 1) * minMoney, maxMoney);
        double money = getRandomVal(minBound, maxBound);

        //微信的随机算法
        //double value = remainMoney / remainUser * 2;
        //money = Math.max(minMoney, money);
        //money = Math.min(maxMoney, money);
        money = Math.floor(money * 100) / 100;
        return money;
    }

    public static void main(String[] args) {
        double minMoney = 100.0;
        double maxMoney = 200.0;

        double totalAns = 0.0;
        double[] amounts = new double[TOTAL_USERS];

        int remainUsers = TOTAL_USERS;
        Double remainMoney = TOTAL_AMOUNT;
        for (int i = 0; i < TOTAL_USERS; i++) {
            amounts[i] = getRandomMoney(remainUsers, remainMoney, minMoney, maxMoney);
            remainUsers--;
            remainMoney -= amounts[i];
        }

        for (Double amount : amounts) {
            totalAns += amount;
        }
        System.out.println(Arrays.toString(amounts));
        System.out.println(String.format("%.2f", totalAns));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值