|
| 1 | +/** |
| 2 | + * 1467. Probability of a Two Boxes Having The Same Number of Distinct Balls |
| 3 | + * https://leetcode.com/problems/probability-of-a-two-boxes-having-the-same-number-of-distinct-balls/ |
| 4 | + * Difficulty: Hard |
| 5 | + * |
| 6 | + * Given 2n balls of k distinct colors. You will be given an integer array balls of size k where |
| 7 | + * balls[i] is the number of balls of color i. |
| 8 | + * |
| 9 | + * All the balls will be shuffled uniformly at random, then we will distribute the first n balls to |
| 10 | + * the first box and the remaining n balls to the other box (Please read the explanation of the |
| 11 | + * second example carefully). |
| 12 | + * |
| 13 | + * Please note that the two boxes are considered different. For example, if we have two balls of |
| 14 | + * colors a and b, and two boxes [] and (), then the distribution [a] (b) is considered different |
| 15 | + * than the distribution [b] (a) (Please read the explanation of the first example carefully). |
| 16 | + * |
| 17 | + * Return the probability that the two boxes have the same number of distinct balls. Answers |
| 18 | + * within 10-5 of the actual value will be accepted as correct. |
| 19 | + */ |
| 20 | + |
| 21 | +/** |
| 22 | + * @param {number[]} balls |
| 23 | + * @return {number} |
| 24 | + */ |
| 25 | +var getProbability = function(balls) { |
| 26 | + const totalBalls = balls.reduce((sum, count) => sum + count, 0); |
| 27 | + const halfBalls = totalBalls / 2; |
| 28 | + let validCombinations = 0; |
| 29 | + let totalCombinations = 0; |
| 30 | + |
| 31 | + calculateCombinations(0, new Array(balls.length).fill(0), halfBalls, 0); |
| 32 | + return validCombinations / totalCombinations; |
| 33 | + |
| 34 | + function countDistinct(config) { |
| 35 | + return config.filter(count => count > 0).length; |
| 36 | + } |
| 37 | + |
| 38 | + function calculateCombinations(index, config, remaining, firstBoxCount) { |
| 39 | + if (index === balls.length) { |
| 40 | + if (firstBoxCount === halfBalls) { |
| 41 | + const secondBox = balls.map((count, i) => count - config[i]); |
| 42 | + if (countDistinct(config) === countDistinct(secondBox)) { |
| 43 | + validCombinations += combinatorialProduct(config) * combinatorialProduct(secondBox); |
| 44 | + } |
| 45 | + totalCombinations += combinatorialProduct(config) * combinatorialProduct(secondBox); |
| 46 | + } |
| 47 | + return; |
| 48 | + } |
| 49 | + |
| 50 | + for (let i = 0; i <= balls[index] && firstBoxCount + i <= halfBalls; i++) { |
| 51 | + if (remaining >= i) { |
| 52 | + config[index] = i; |
| 53 | + calculateCombinations(index + 1, config, remaining - i, firstBoxCount + i); |
| 54 | + config[index] = 0; |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + function combinatorialProduct(config) { |
| 60 | + const numerator = factorial(halfBalls); |
| 61 | + let denominator = 1; |
| 62 | + for (const count of config) { |
| 63 | + denominator *= factorial(count); |
| 64 | + } |
| 65 | + return numerator / denominator; |
| 66 | + } |
| 67 | + |
| 68 | + function factorial(n) { |
| 69 | + let result = 1; |
| 70 | + for (let i = 2; i <= n; i++) { |
| 71 | + result *= i; |
| 72 | + } |
| 73 | + return result; |
| 74 | + } |
| 75 | +}; |
0 commit comments