面试遇到怪题,大家有什么思路吗

209 天前
 tenserG

分红包,上限是总奖金 30%,下线 1 元,输入奖金总数 m 和人数 n ,输出一个列表表示每个人红包

思路一 传统分红包办法,1 到 n-1 人领随机生成 range ( 1 ,0.3*m )的红包,最后一个人拿到剩余,但是这样最后一个人可能会超出上下限

思路二 下限当作保底,先每个人分 1 元保底,剩下奖金池是 m-n ,1 到 n-1 人领取随机生成 range ( 0 ,0.3*m-1 )的红包,最后一个人拿到剩余,这样保证了下限,但是上限还是会超,如果前面 n-1 个人没分完总奖金的( 1-30%)=70%,剩下一个人就会超过上限 30%

到这里基本时间就到了,感觉凉凉,复盘时候感觉无论怎么随机分,都没法保证刚好分完

思路三是搜索到的一种解法,先计算平均值 avg ,每个人两两一对,领取 avg+-random 的红包,如果人数是单数,则返回平均值。这样能保证分完,不过额真的随机么。

6645 次点击
所在节点    算法
53 条回复
Huelse
209 天前
在创建红包的时候就按数量分好金额池,然后随机抽就完了
viking602
209 天前
@xierqii 回答技术问题不能用 AI 你是一点都不看 @livid
Livid
209 天前
@viking602 谢谢。那个账号已经被彻底 ban 。
gwbw
209 天前
思路三没什么问题,你可能纠结的"随机"是数学上的随机,工程上只要在最后分的时候把顺序打乱,整体就是公平的。类似于切蛋糕的和分蛋糕的不是同一个人,无论切蛋糕的人怎么切,只要分蛋糕的人闭着眼睛随机分,大家的期望就都一样
yankebupt
209 天前
哎……多少次了,AI 回答贴个分享链接就行了不要贴结果不要贴结果,又拜拜了一个账号
yc8332
209 天前
上下限差太多,又限制单包。。基本下限就没用了。
a222QAQ
209 天前
@phpfpm @Exxfire 超过 30%不用重新 roll ,直接分给下一个不到 30%的
bloodspasm
209 天前
如果是 2 个人分 100 块钱, 会怎么样? 😅
vincentWdp
209 天前
1 楼的答案很好啊. 补充一下:
1. 可以先做判断, 对不能满足情况的输入进行报错.
2. 再看 47 楼的回答, 也就是 roll 的时候, 把已经达到上限的元素剔除就好了
BreadKiller
209 天前
想了一下,感觉只能事先按人数分配好红包金额,不能每次去获取的时候再去计算红包金额。在此前提下,想了一个方案:
首先给每个人分配下限 1
然后循环 每次随机取 1 人 然后再在 0.3m-已分配给这个人的金额 中随机一个金额
判断这个随机金额+已分配金额是否达到 m ,没达到就给这个人分配这个随机的金额,继续循环
如果这个随机金额+已分配金额超过了 m ,那随机金额就取 m-已分配金额,结束循环

用 js 写了一下 金额是乘了 100 用整数算
```
function calc(m, n) {
const min = 100;
const max = 0.3 * m;
const res = new Array(n).fill(min);
let sum = res.reduce((a, b) => a + b, 0);

while (sum < m) {
const i = Math.floor(Math.random() * n);
let rand = Math.floor(Math.random() * (max - res[i]));
if (sum + rand > m) {
rand = m - sum;
}
res[i] += rand;
sum = res.reduce((a, b) => a + b, 0);
}
console.log(sum, res);
}
```
lff0305
208 天前
每个人依次生成随机数,如果满足条件且小于剩余钱数,给这个人分钱,对下一个人;
如果到了最后一个人那么判断剩余钱数是否满足条件。如果 OK 那么找到一个方案。否则前一个人重新来


import java.util.Arrays;
import java.util.Random;

public class RedBag {

private Random random = new Random();

public static void main(String[] args) {
int[] r = new RedBag().resolve(new int[10], 10,0, 100, 100);
System.out.println(Arrays.toString(r));
r = new RedBag().resolve(new int[10], 10, 0, 10, 10);
System.out.println(Arrays.toString(r));
}

/// result: Result for each persion
/// N: Total number of person
/// n: Current person, [0, N - 1]
/// M: Total money
/// m: How much money left
private int[] resolve(int[] result, int N, int n, int M, int m) {

// Last person, and the left money is OK
if (n == N - 1) {
if (m >= 1 && m < 0.3 * M) {
result[n] = m;
return result;
} else {
return null;
}
}

// left money cannot give at least $1 per person
if (m < N - n) {
return null;
}

int value = 0;
while (true) {
// Try to give some money to current person
int range = Math.min(m, (int) Math.floor(0.3 * M));
value = random.nextInt(range) + 1;
if (value < m) {
result[n] = value;
int[] r = resolve(result, N, n + 1, M, m - value);
if (r != null) {
return r;
}
}
}
}
}
rainbowhu
208 天前
这样的吗?

对于总量 m 和个数 n ,以及最大比例 r, 每次确定随机范围[x, y]

x >= 1
m - x <= (n - 1) * r * m 也即 x >= m - (n - 1) * r * m

-> x = max(1, m - (n - 1) * r * m)

y <= r * m
m - y >= (n - 1) * 1 也即 y <= m - (n - 1) * 1

-> y = min(r * m, m - (n - 1) * 1)
rainbowhu
208 天前
@rainbowhu r * m 直接换成固定值 最早的 m * 0.3 吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1124068

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX