【Java】RedPacketUtils(红包分配算法)

一个不严谨的红包分配算法

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class RedPacketUtils {

    /**
     * 红包分配算法
     * 
     * @param total     总金额 (单位: 分)
     * @param count     总份数
     * @return
     */
    public static List<Integer> random(final int total, final int count) {
        if (total <= 0) { 
            throw new IllegalArgumentException("The total must be greater than 0.");
        }
        if (count <= 0) { 
            throw new IllegalArgumentException("The count must be greater than 0.");
        }
        int restMoney = total;
        int restCount = count;
        Random random = ThreadLocalRandom.current();
        List<Integer> data = new ArrayList<Integer>(count);
        // 随机发前 totalCount - 1 个红包, 最后一个不需要随机
        for (int i = 0; i < count - 1; i++) {
            // 最少1分钱, 最多不超过剩下金额平均数的2倍
            int threshold = (restMoney / restCount * 2);
            int item = random.nextInt(threshold) + 1;
            data.add(item);
            restMoney -= item;
            restCount--;
        }
        // 最后一个红包不需要随机
        data.add(restMoney);
        return data;
    }

    /**
     * 红包分配算法
     * 
     * @param total     总金额 (单位: 分)
     * @param count     总份数
     * @param min       包下限 (单位: 分)
     * @param max       包上限 (单位: 分)
     * @param factor    浮动阈 [0.0f, 1.0f]
     * @return
     */
    public static List<Integer> random(final int total, final int count, 
                                       final int min, final int max, final float factor) {
        if (total <= 0) { 
            throw new IllegalArgumentException("The total must be greater than 0.");
        }
        if (count <= 0) { 
            throw new IllegalArgumentException("The count must be greater than 0.");
        }
        if (min <= 0) { 
            throw new IllegalArgumentException("The min must be greater than 0.");
        }
        if (max <= 0) { 
            throw new IllegalArgumentException("The max must be greater than 0.");
        }
        if (total < count * min || total > count * max) {
            throw new IllegalArgumentException("The total must be between count * min and count * max.");
        }
        if (factor < 0.0f || factor > 1.0f) {
            throw new IllegalArgumentException("The factor must be between 0 and 1.");
        }
        Random random = ThreadLocalRandom.current();
        List<Integer> data = new ArrayList<Integer>(count);
        // 平均分配红包
        int avg = total / count;
        int rest = total - avg * count;
        for (int i = 0; i < count; i++) {
            data.add(i < rest ? avg + 1 : avg);
        }
        // 根据浮动阈重新标定
        if (factor <= 0 || factor > 1) {
            return data;
        }
        for (int i = 0; i < count - 1; i++) {
            int itemThis = data.get(i);
            int itemNext = data.get(i + 1);
            boolean isLt = itemThis < itemNext;
            int rangeThis = isLt ? max - itemThis : itemThis - min;
            int rangeNext = isLt ? itemNext - min : max - itemNext;
            int rangeBound = (int) Math.ceil(factor * (Math.min(rangeThis, rangeNext) + 1));
            int mark = random.nextInt(rangeBound) + 1;
            int rule = isLt ? mark : -mark;
            data.set(i, data.get(i) + rule);
            data.set(i + 1, data.get(i + 1) - rule);
        }
        return data;
    }

}
posted @ 2020-12-10 20:29  XKIND  阅读(198)  评论(0编辑  收藏  举报