Last active
January 20, 2019 16:53
-
-
Save fei-ke/2e86bce8aa52bff5d0bf to your computer and use it in GitHub Desktop.
红包生成算法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Random; | |
/** | |
* Created by fei-ke on 2015/6/18. | |
*/ | |
public class RedPackAmountGenerator { | |
private int mFloor; //下限 | |
private int mCeiling; //上限 | |
private int mCount; //数量 | |
private int mTotal; //金额 | |
private int mCurrent; //当前游标 | |
/** | |
* @param total 金额 | |
* @param count 总个数(为0时自动根据上下限估算个数) | |
* @param floor 下限 | |
* @param ceiling 上限 | |
* @param floatRange 浮动范围(在平均值左右浮动的范围) | |
*/ | |
public RedPackAmountGenerator(int total, int count, int floor, int ceiling, float floatRange) { | |
this.mTotal = total; | |
this.mCount = count; | |
int avg; | |
if (count != 0) { | |
avg = total / count; | |
} else { | |
avg = (floor + ceiling) / 2; | |
this.mCount = total / avg; | |
} | |
this.mFloor = Math.max(floor, (int) (avg - avg * floatRange)); | |
this.mCeiling = Math.min(ceiling, (int) (avg + avg * floatRange)); | |
this.mCurrent = 1; | |
} | |
/** | |
* 产生下一个随机数 | |
* | |
* @param current 当前第几个人(从1开始) | |
* @param leftAmount 剩余金额 | |
* @return | |
*/ | |
public int next(int current, int leftAmount) { | |
this.mCurrent = current; | |
this.mTotal = leftAmount; | |
Range range = curRange(); | |
if (range.ceiling == range.floor) return range.ceiling; | |
Random r = new Random(); | |
//nextInt范围为左闭右开区间,右值+1 | |
int next = r.nextInt(range.ceiling + 1 - range.floor) + range.floor; | |
this.mTotal -= next; | |
this.mCurrent++; | |
return next; | |
} | |
/** | |
* 检查金额人数上下限和浮动范围是否合理 | |
* | |
* @return | |
*/ | |
public boolean isOK() { | |
return mTotal >= mCount * mFloor && mTotal <= mCount * mCeiling; | |
} | |
/** | |
* 产生下一个随机数,当前人数和剩余金额由内部记录 | |
* | |
* @return | |
*/ | |
public int next() { | |
return next(mCurrent, mTotal); | |
} | |
/** | |
* 一次性生成所有随机数 | |
* | |
* @return | |
*/ | |
public List all() { | |
ArrayList list = new ArrayList(); | |
for (int i = mCurrent; i <= mCount; i++) { | |
int next = next(); | |
list.add(next); | |
} | |
return list; | |
} | |
/** | |
* 计算本次随机的范围 | |
*/ | |
private Range curRange() { | |
//本次生成之后剩余个数 | |
int leftCount = mCount - mCurrent; | |
if (leftCount == 0) { | |
return new Range(mTotal, mTotal); | |
} | |
//需要剩下最少的值 | |
int minLeft = leftCount * this.mFloor; | |
//需要剩下最大的值 | |
int maxLeft = Math.min(leftCount * this.mCeiling, mTotal - this.mFloor); | |
//本次随机的下限:max(本次可取最小值,基本下限,浮动范围下限) | |
int rangeFloor = Math.max(mTotal - maxLeft, this.mFloor); | |
//本次随机的上限:min(基本上限,本次可取最大值,浮动范围上限) | |
int rangeCeiling = Math.min(this.mCeiling, mTotal - minLeft); | |
return new Range(rangeFloor, rangeCeiling); | |
} | |
/* static int min(int... nums) { | |
int min = nums[0]; | |
for (int i = 1; i < nums.length; i++) { | |
if (nums[i] < min) { | |
min = nums[i]; | |
} | |
} | |
return min; | |
} | |
static int max(int... nums) { | |
int max = nums[0]; | |
for (int i = 1; i < nums.length; i++) { | |
if (nums[i] > max) { | |
max = nums[i]; | |
} | |
} | |
return max; | |
}*/ | |
/** | |
* 随机范围辅助类 | |
*/ | |
private static class Range { | |
int floor; //下限 | |
int ceiling; //上限 | |
public Range(int floor, int ceiling) { | |
this.floor = floor; | |
this.ceiling = ceiling; | |
} | |
} | |
public static void main(String[] args) { | |
int amount = 500; | |
int person = 40; | |
RedPackAmountGenerator generator = new RedPackAmountGenerator(amount, person, 1, 200, 0.8f); | |
System.out.println("amount:" + amount + ", person:" + person); | |
if (!generator.isOK()) { | |
System.out.println("不合理"); | |
return; | |
} | |
System.out.println(generator.all()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment