日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法

發(fā)布時間:2023/12/19 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

如何用 js 實現(xiàn)一個類似微信紅包的隨機(jī)算法

js, 微信紅包, 隨機(jī)算法

"use strict";

/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2020-09-16
* @modified
*
* @description 如何用 js 實現(xiàn)一個類似微信紅包的隨機(jī)算法, 最簡單的方法實現(xiàn)微信紅包的隨機(jī)算法
* @difficulty Hard
* @complexity O(n)
* @augments
* @example
* @link https://www.cnblogs.com/xgqfrms/p/13689802.html
* @link https://www.cnblogs.com/xgqfrms/tag/%E7%BA%A2%E5%8C%85/
* @link https://www.zhihu.com/question/22625187/answer/1478941580
* @solutions
*
*/

const log = console.log;

const shuffle = (arr = []) => {
let len = arr.length;
while (len > 1){
const index = Math.floor(Math.random() * len--);
[
arr[len],
arr[index],
] = [
arr[index],
arr[len],
];
}
return arr;
}


/**
算法需要滿足條件:
1. 每個人都可以分到至少 0.01 元;
2. 所有人的分到的紅包之和與發(fā)出的金額相等,不多不少,剛好分完;
3. 每個人分到金額的概率相等;
*/

/**
假設(shè),發(fā)出一個 100元紅包,給 10個人分!
算法實現(xiàn):
1. 按照人數(shù),生成一個等長的數(shù)組,且每一個元素的初始化值為 0.01;?
2. 將剩余的金額(100 - 10 * 0.01), 按照微信設(shè)計的規(guī)則(假如是正態(tài)分布)進(jìn)行分配出 10 份; ?
3. 將分配好的紅包,依次加入到生成的數(shù)組中;?
4. 最后使用 shuffle 算法打亂數(shù)組,并返回; ?
5. 將計算好的數(shù)組,按照搶紅包的順序作為索引值依次取出紅包即可.?
*/

// 精度損失解決方案, 擴(kuò)大后,再還原 ??
const autoRandomRedPackage = (money, num, limit = 0.01) => {
if((money / num) < limit) {
// alert
log(`? 請重新輸入紅包數(shù)量! 減少紅包數(shù)量,或增加紅包金額!`);
log(`? 你輸入的紅包數(shù)量太多了,每個人至少要能分到 0.01 元!`);
return false;
} else {
const originMoney = money;
const originLimit = limit;
let multi = 100 * (100 / money);
money *= multi;
limit *= multi;
// log(`multi =`, multi);
const result = [...new Uint8Array(num)].fill(limit, 0, num);
// 1. 將剩余的紅包,均分?,如果有余數(shù),隨機(jī)的添加到數(shù)組的一個元素上
const restLimit = (money - limit * num) / limit;
const reminderLimit = (restLimit % num);
const reminderMoney = reminderLimit * limit;
const averageLimit = (restLimit - reminderLimit) / num;
for (let i = 0; i < num; i++) {
const index = parseInt(Math.random() * averageLimit);
const randomMoney = index * limit;
const leftMoney = (averageLimit - index) * limit;
// 2. 在平均后的范圍內(nèi),計算出一個隨機(jī)數(shù),將分配好的紅包,依次加入到生成的數(shù)組中;?
result[i] += randomMoney;
// 3. 分配后剩余的紅包,隨機(jī)加入到生成的數(shù)組中;?
const j = parseInt(Math.random() * num);
result[j] += leftMoney;
}
// 4. 將平均后的余數(shù)紅包,隨機(jī)加入到生成的數(shù)組中;?
if(reminderMoney > 0) {
const index = parseInt(Math.random() * num);
result[index] += reminderMoney;
}
const temp = shuffle(result).map(i => i / multi);
// log(`temp =`, temp);
const total = temp.reduce((acc, i) => acc += i*multi, 0) / multi;
// log(`total !== originMoney`, total !== originMoney, total, originMoney);
if(total !== originMoney) {
return autoRandomRedPackage(originMoney, num, originLimit);
}
const [min, ...rest1] = temp.sort((a, b) => a - b > 0 ? 1 : -1);
const [max, ...rest2] = temp.sort((a, b) => a - b > 0 ? -1 : 1);
return {
total: total,
result: temp,
desc: `
???♂? 你輸入的紅包總額是 ${originMoney} 元, 紅包數(shù)量是 ${num} 個!
? 最大的紅包是 ${max} 元!
? 最小的紅包是 ${min} 元!
`,
// desc: `
// ???♂? 你輸入的紅包總額是 ${originMoney} 元, 紅包數(shù)量是 ${num} 個!\n
// ? 最大的紅包是 ${max} 元!\n
// ? 最小的紅包是 ${min} 元!\n
// `,
};
// return temp;
}
}

const total = arr => arr.result.reduce((acc, i) => acc += i*100, 0) / 100;

// 測試
const test = autoRandomRedPackage(0.1, 11);// ? 異常處理
const test0 = autoRandomRedPackage(0.1, 5);
const test1 = autoRandomRedPackage(0.1, 10); // ? ok
const test2 = autoRandomRedPackage(1, 10);
const test3 = autoRandomRedPackage(10, 10);
const test4 = autoRandomRedPackage(100, 10);
const test5 = autoRandomRedPackage(100, 11);

log(`\ntest =`, test);
log(`total =`, test && total(test));

log(`\ntest =`, test0);
log(`total =`, test0 && total(test0));

log(`\ntest =`, test1);
log(`total =`, test1 && total(test1));

log(`\ntest =`, test2);
log(`total =`, test2 && total(test2));

log(`\ntest =`, test3);
log(`total =`, test3 && total(test3));

log(`\ntest =`, test4);
log(`total =`, test4 && total(test4));

log(`\ntest =`, test5);
log(`total =`, test5 && total(test5));


/*
$ node node perfect-solution.js
? 請重新輸入紅包數(shù)量! 減少紅包數(shù)量,或增加紅包金額!
? 你輸入的紅包數(shù)量太多了,每個人至少要能分到 0.01 元!
test = false
total = false
test = {
total: 0.1,
result: [ 0.03, 0.03, 0.02, 0.01, 0.01 ],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 0.1 元, 紅包數(shù)量是 5 個!\n' +
' ? 最大的紅包是 0.03 元!\n' +
' ? 最小的紅包是 0.01 元!\n' +
' '
}
total = 0.1
test = {
total: 0.1,
result: [
0.01, 0.01, 0.01,
0.01, 0.01, 0.01,
0.01, 0.01, 0.01,
0.01
],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 0.1 元, 紅包數(shù)量是 10 個!\n' +
' ? 最大的紅包是 0.01 元!\n' +
' ? 最小的紅包是 0.01 元!\n' +
' '
}
total = 0.1
test = {
total: 1,
result: [
0.16, 0.13, 0.13,
0.12, 0.09, 0.08,
0.08, 0.08, 0.07,
0.06
],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 1 元, 紅包數(shù)量是 10 個!\n' +
' ? 最大的紅包是 0.16 元!\n' +
' ? 最小的紅包是 0.06 元!\n' +
' '
}
total = 1
test = {
total: 10,
result: [
2.43, 1.73, 1.43,
1.36, 1, 0.78,
0.66, 0.28, 0.25,
0.08
],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 10 元, 紅包數(shù)量是 10 個!\n' +
' ? 最大的紅包是 2.43 元!\n' +
' ? 最小的紅包是 0.08 元!\n' +
' '
}
total = 10
test = {
total: 100,
result: [
23.71, 16.9, 13.24,
12, 10, 8.6,
8.33, 3.6, 1.92,
1.7
],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 100 元, 紅包數(shù)量是 10 個!\n' +
' ? 最大的紅包是 23.71 元!\n' +
' ? 最小的紅包是 1.7 元!\n' +
' '
}
total = 100
test = {
total: 100,
result: [
17.59, 11.68, 11.55,
10.2, 8.83, 8.81,
8.24, 7.55, 7.44,
6.66, 1.45
],
desc: '\n' +
' ???♂? 你輸入的紅包總額是 100 元, 紅包數(shù)量是 11 個!\n' +
' ? 最大的紅包是 17.59 元!\n' +
' ? 最小的紅包是 1.45 元!\n' +
' '
}
total = 100
*/


refs

https://www.cnblogs.com/xgqfrms/tag/紅包/


?xgqfrms 2012-2020

www.cnblogs.com 發(fā)布文章使用:只允許注冊用戶才可以訪問!


xgqfrms

標(biāo)簽:?微信,?隨機(jī)算法,?紅包,?js,?微信紅包

總結(jié)

以上是生活随笔為你收集整理的js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。