一个不严谨的红包分配算法
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;
}
}