|
| 1 | +// Runtime: 238 ms (Top 80.0%) | Memory: 58.10 MB (Top 20.0%) |
| 2 | + |
| 3 | +/** |
| 4 | +* @param {number[]} balls |
| 5 | +* @return {number} |
| 6 | +*/ |
| 7 | +var getProbability = function(balls) |
| 8 | +{ |
| 9 | + var k = balls.length; |
| 10 | + var halfUsed = balls.reduce((acc,val)=>acc+val,0)/2; |
| 11 | + var startArray = new Array(k); |
| 12 | + startArray.fill(0); |
| 13 | + |
| 14 | + const perm = function(b1,b2) |
| 15 | + { |
| 16 | + var p1, p2, s1, s2; |
| 17 | + |
| 18 | + s1 = b1.reduce((acc,val)=>acc+val,0); |
| 19 | + s2 = b2.reduce((acc,val)=>acc+val,0); |
| 20 | + |
| 21 | + const fact = function(n) |
| 22 | + { |
| 23 | + var f=1; |
| 24 | + for(let i=2; i<=n; i++) |
| 25 | + f *= i; |
| 26 | + return f; |
| 27 | + }; |
| 28 | + |
| 29 | + p1 = fact(s1); |
| 30 | + p2 = fact(s2); |
| 31 | + |
| 32 | + b1.forEach(val=>{if(val>1)p1/=fact(val);}); |
| 33 | + b2.forEach(val=>{if(val>1)p2/=fact(val);}); |
| 34 | + |
| 35 | + return p1*p2; |
| 36 | + }; |
| 37 | + |
| 38 | + const getValidCombos = function(ballsUsed,colorNum=0) |
| 39 | + { |
| 40 | + var box1Used = ballsUsed.reduce((acc,val)=>acc+val,0); |
| 41 | + var matches = {good:0,total:0}, thisColorMax = halfUsed - box1Used; |
| 42 | + |
| 43 | + if(colorNum === k-1) |
| 44 | + { |
| 45 | + /* |
| 46 | + Last ball color - adjust # of balls of this color to equal half |
| 47 | + (if possible). Then count # of different balls in each box. |
| 48 | + */ |
| 49 | + if(thisColorMax > balls[colorNum]) |
| 50 | + return {good:0,total:0}; |
| 51 | + |
| 52 | + ballsUsed[colorNum] = thisColorMax; |
| 53 | + let ballsLeft = []; |
| 54 | + let colorsUsed = [0,0]; |
| 55 | + for(let i=0; i<k; i++) |
| 56 | + { |
| 57 | + ballsLeft[i] = balls[i] - ballsUsed[i]; |
| 58 | + if(ballsUsed[i] > 0) |
| 59 | + colorsUsed[0]++; |
| 60 | + if(ballsLeft[i] > 0) |
| 61 | + colorsUsed[1]++; |
| 62 | + } |
| 63 | + |
| 64 | + /* Count the # of permutations for the boxes represented by this 1 combination. */ |
| 65 | + let permutations = perm(ballsUsed,ballsLeft,k); |
| 66 | + return {good:(colorsUsed[1] === colorsUsed[0]) ? permutations : 0, total:permutations}; |
| 67 | + } |
| 68 | + |
| 69 | + thisColorMax = Math.min(thisColorMax,balls[colorNum]); |
| 70 | + for(let i=0; i<=thisColorMax; i++) |
| 71 | + { |
| 72 | + let match = getValidCombos([...ballsUsed], colorNum+1); |
| 73 | + matches = {good:matches.good+match.good, total:matches.total+match.total}; |
| 74 | + ballsUsed[colorNum]++; |
| 75 | + } |
| 76 | + return matches; |
| 77 | + } |
| 78 | + |
| 79 | + /* Probability = (total # of permutations with equal # of balls) / (permutations with same # of unique balls) */ |
| 80 | + let res = getValidCombos(startArray); |
| 81 | + return res.good/res.total; |
| 82 | +}; |
0 commit comments