2
* @param {number[]} balls5
var getProbability = function (balls) {7
var halfUsed = balls.reduce((acc, val) => acc + val, 0) / 2;8
var startArray = new Array(k);11
const perm = function (b1, b2) {14
s1 = b1.reduce((acc, val) => acc + val, 0);15
s2 = b2.reduce((acc, val) => acc + val, 0);17
const fact = function (n) {19
for (let i = 2; i <= n; i++) f *= i;27
if (val > 1) p1 /= fact(val);30
if (val > 1) p2 /= fact(val);36
const getValidCombos = function (ballsUsed, colorNum = 0) {37
var box1Used = ballsUsed.reduce((acc, val) => acc + val, 0);38
var matches = { good: 0, total: 0 },39
thisColorMax = halfUsed - box1Used;41
if (colorNum === k - 1) {43
Last ball color - adjust # of balls of this color to equal half44
(if possible). Then count # of different balls in each box.46
if (thisColorMax > balls[colorNum]) return { good: 0, total: 0 };48
ballsUsed[colorNum] = thisColorMax;50
let colorsUsed = [0, 0];51
for (let i = 0; i < k; i++) {52
ballsLeft[i] = balls[i] - ballsUsed[i];53
if (ballsUsed[i] > 0) colorsUsed[0]++;54
if (ballsLeft[i] > 0) colorsUsed[1]++;57
/* Count the # of permutations for the boxes represented by this 1 combination. */58
let permutations = perm(ballsUsed, ballsLeft, k);60
good: colorsUsed[1] === colorsUsed[0] ? permutations : 0,65
thisColorMax = Math.min(thisColorMax, balls[colorNum]);66
for (let i = 0; i <= thisColorMax; i++) {67
let match = getValidCombos([...ballsUsed], colorNum + 1);69
good: matches.good + match.good,70
total: matches.total + match.total,72
ballsUsed[colorNum]++;77
/* Probability = (total # of permutations with equal # of balls) / (permutations with same # of unique balls) */78
let res = getValidCombos(startArray);79
return res.good / res.total;