抢红包算法

        红包算法有很多,比如二倍均值法,线段切割法等。一般来说,需要满足的规则有以下几点:

        1. 所有人抢到的金额之和要等于红包金额,不能多也不能少。
        2. 每个人至少抢到1分钱。
        3. 要保证红包拆分的金额尽可能分布均衡,不要出现两极分化太严重的情况。

public class RedPackage {
    public static void main(String[] args) {
        RedPackage redPackage = new RedPackage();
        redPackage.print(redPackage.divideRedPackageV1(5, 1));
        redPackage.print(redPackage.divideRedPackageV1(5, 5));
        redPackage.print(redPackage.divideRedPackageV1(100, 5));
        redPackage.print(redPackage.divideRedPackageV2(5, 1));
        redPackage.print(redPackage.divideRedPackageV2(5, 5));
        redPackage.print(redPackage.divideRedPackageV2(100, 5));
    }

    private void print(List<Integer> list) {
        for (Integer amount : list) {
            System.out.print(amount + " ");
        }
        System.out.println();
    }


    /**
     * 拆分红包-二倍均值法,每个红包的大小为:[1,(剩余红包金额/剩余人数 )* 2-1]
     * 注意边界:如5分钱红包发5个人
     *
     * @param totalAmount 总金额 分
     * @param personNum   总人数
     * @return 红包金额集合
     */
    private List<Integer> divideRedPackageV1(Integer totalAmount, Integer personNum) {
        List<Integer> amountList = new LinkedList<>();
        Random random = new Random();
        Integer leftAmount = totalAmount;
        Integer leftPerson = personNum;
        for (int i = 0; i < personNum - 1; i++) {
            //二倍均值法
            Integer amount = random.nextInt(leftAmount / leftPerson * 2 - 1) + 1;
            amountList.add(amount);
            leftAmount -= amount;
            leftPerson--;
        }
        amountList.add(leftAmount);
        return amountList;
    }

    /**
     * 拆分红包-线段切割法,[1,总金额-1]
     * 将红包比作一条线段,对线段进行personNum-1次,即分成personNum段。
     * 每一段的长度即为红包的大小
     *
     * @param totalAmount 总金额 分
     * @param personNum   总人数
     * @return 红包金额集合
     */
    private List<Integer> divideRedPackageV2(Integer totalAmount, Integer personNum) {
        List<Integer> separateList = new LinkedList<>();
        List<Integer> amountList = new LinkedList<>();
        if (personNum == 1) {
            amountList.add(totalAmount);
            return amountList;
        }
        Random random = new Random();
        while (separateList.size() < personNum - 1) {
            //对红包线段切割personNum - 1次
            Integer separate = random.nextInt(totalAmount - 1) + 1;
            if (separateList.contains(separate)) {
                continue;
            }
            separateList.add(separate);
        }
        separateList.add(0);
        separateList.add(totalAmount);
        //集合排序
        Collections.sort(separateList);
        //计算线段长度即红包大小
        for (int i = 0; i < separateList.size() - 1; i++) {
            amountList.add(separateList.get(i + 1) - separateList.get(i));
        }
        return amountList;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值