Find Missing Observations
MedPrompt
You have observations of n + m 6-sided dice rolls with each face numbered from 1 to 6. n of the observations went missing, and you only have the observations of m rolls. Fortunately, you have also calculated the average value of the n + m rolls.
You are given an integer array rolls of length m where rolls[i] is the value of the ith observation. You are also given the two integers mean and n.
Return an array of length n containing the missing observations such that the average value of the n + m rolls is exactly mean. If there are multiple valid answers, return any of them. If no such array exists, return an empty array.
The average value of a set of k numbers is the sum of the numbers divided by k.
Note that mean is an integer, so the sum of the n + m rolls should be divisible by n + m.
Example 1:
Input: rolls = [3,2,4,3], mean = 4, n = 2
Output: [6,6]
Explanation: The mean of all n + m rolls is (3 + 2 + 4 + 3 + 6 + 6) / 6 = 4.Example 2:
Input: rolls = [1,5,6], mean = 3, n = 4
Output: [2,3,2,2]
Explanation: The mean of all n + m rolls is (1 + 5 + 6 + 2 + 3 + 2 + 2) / 7 = 3.Example 3:
Input: rolls = [1,2,3,4], mean = 6, n = 4
Output: []
Explanation: It is impossible for the mean to be 6 no matter what the 4 missing rolls are.
Constraints:
m == rolls.length1 <= n, m <= 1051 <= rolls[i], mean <= 6
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves exploring all possible combinations for the n missing dice rolls using recursion. For each of the n missing rolls, we try every possible value from 1 to 6. If a combination results in the desired total mean, we have found a solution. While this approach is conceptually straightforward, it is computationally very expensive.
Algorithm
- Calculate
m = rolls.length. - Calculate
sum_m, the sum of elements inrolls. - Calculate the target sum for the missing rolls:
missingSum = mean * (n + m) - sum_m. - Define a recursive backtracking function, e.g.,
backtrack(index, currentSum, combination). - The function tries to fill the
combinationarray from the givenindex. - Base Case: If
index == n, check ifcurrentSum == missingSum. If they match, a solution has been found. Store it and returntrue. - Recursive Step: Iterate through dice values
vfrom 1 to 6. For eachv:- Place
vatcombination[index]. - Make a recursive call:
backtrack(index + 1, currentSum + v, combination). - If the recursive call returns
true, it means a solution was found, so propagatetrueup the call stack.
- Place
- Pruning: Before the loop, add checks to prune impossible branches. If the minimum possible sum from the current state (
currentSum + (n - index) * 1) is already greater thanmissingSum, or the maximum possible sum (currentSum + (n - index) * 6) is less thanmissingSum, then this path cannot lead to a solution, so returnfalse. - If the initial
missingSumis impossible (i.e., less thannor greater than6*n), return an empty array immediately.
Walkthrough
First, we determine the required sum of the n missing rolls. The total sum of all n + m rolls is mean * (n + m). By subtracting the sum of the known m rolls, we get the target sum for the missing n rolls, let's call it missingSum.
We then use a backtracking algorithm to find a sequence of n numbers (from 1 to 6) that add up to missingSum. The algorithm works as follows:
We define a recursive function that attempts to build the array of missing rolls one element at a time. For the first missing roll, it tries placing a 1, then recurses to find the rest of the sum. If that fails, it backtracks and tries placing a 2, and so on, up to 6.
To avoid unnecessary computation, we can add pruning to the backtracking function. At any step, if we know that it's impossible to reach missingSum from the current state (e.g., the remaining sum needed is too high or too low for the number of rolls left), we can stop exploring that path. Despite pruning, the worst-case time complexity remains exponential.
class Solution { private int[] result; private int n_val; private int targetSum; public int[] missingRolls(int[] rolls, int mean, int n) { this.n_val = n; int m = rolls.length; int sum_m = 0; for (int roll : rolls) { sum_m += roll; } this.targetSum = mean * (n + m) - sum_m; if (targetSum < n || targetSum > 6 * n) { return new int[0]; } this.result = null; findCombination(0, 0, new int[n]); return result == null ? new int[0] : result; } private boolean findCombination(int k, int currentSum, int[] combination) { if (k == n_val) { if (currentSum == targetSum) { this.result = combination.clone(); return true; } return false; } // Pruning if (currentSum + (n_val - k) * 1 > targetSum || currentSum + (n_val - k) * 6 < targetSum) { return false; } for (int v = 1; v <= 6; v++) { combination[k] = v; if (findCombination(k + 1, currentSum + v, combination)) { return true; } } return false; }}Complexity
Time
O(6^n) - In the worst case, the algorithm explores all `6^n` possible combinations for the `n` missing rolls. Pruning can reduce the search space in practice, but the worst-case complexity remains exponential.
Space
O(n) - The space is dominated by the recursion stack depth, which can go up to `n` in the worst case. We also need O(n) space to store the combination being built.
Trade-offs
Pros
Guaranteed to find a solution if one exists.
Serves as a fundamental approach that can be applied to a wide range of combinatorial search problems.
Cons
Extremely inefficient due to its exponential time complexity.
Will result in a 'Time Limit Exceeded' error for the given constraints where
ncan be up to 10^5.
This optimal approach avoids any form of exhaustive search by using a direct mathematical calculation. It first computes the exact sum required for the n missing rolls. Then, it checks if this sum is achievable with n dice (each roll between 1 and 6). If it is, it constructs a valid solution by distributing the required sum as evenly as possible among the n rolls.
Algorithm
- Calculate
m, the number of given rolls (rolls.length). - Calculate
sum_m, the sum of all elements in therollsarray. - Calculate the total sum required for all
n + mrolls to have the givenmean:totalSum = mean * (n + m). - Determine the required sum for the
nmissing rolls:missingSum = totalSum - sum_m. - Check if a solution is possible. The sum of
ndice rolls must be betweenn * 1andn * 6. IfmissingSum < normissingSum > 6 * n, no solution exists, so return an empty array. - If a solution is possible, construct the result array
ansof sizen. - Distribute the
missingSumas evenly as possible. Calculate the base value for each roll:base = missingSum / n. - Calculate the remainder:
rem = missingSum % n. - This means
remrolls will bebase + 1andn - remrolls will bebase. - Fill the
ansarray: iterate fromi = 0ton-1. Setans[i] = base. Ifi < rem, add 1 toans[i]. - Return the constructed
ansarray.
Walkthrough
The core idea is based on the definition of the mean. The total sum of all n + m rolls must be mean * (n + m).
-
Calculate Missing Sum: We first find the sum of the
mrolls we already have. Then, we subtract this from the required total sum to find the sum needed for thenmissing rolls. Let's call thismissingSum.missingSum = (mean * (n + m)) - sum(rolls) -
Check Feasibility: A die roll must be an integer between 1 and 6. Therefore, the sum of
ndice rolls must be at leastn * 1 = nand at mostn * 6 = 6n. If our calculatedmissingSumis outside this range[n, 6n], it's impossible to find a solution, so we return an empty array. -
Construct Solution: If
missingSumis within the valid range, a solution is guaranteed to exist. We can construct one such solution by distributing themissingSumas evenly as possible across thenrolls. We calculate abasevalue for each roll using integer division (missingSum / n) and aremainder(missingSum % n). This meansremainderrolls will have a value ofbase + 1, and the othern - remainderrolls will have a value ofbase. Since we've already passed the feasibility check, these constructed roll values are guaranteed to be between 1 and 6.
class Solution { public int[] missingRolls(int[] rolls, int mean, int n) { int m = rolls.length; int currentSum = 0; for (int roll : rolls) { currentSum += roll; } // Calculate the sum required for the n missing rolls int missingSum = mean * (n + m) - currentSum; // Check if this sum is possible with n dice if (missingSum < n || missingSum > 6 * n) { return new int[0]; } // Distribute the missingSum among n rolls int[] result = new int[n]; int baseValue = missingSum / n; int remainder = missingSum % n; for (int i = 0; i < n; i++) { result[i] = baseValue; if (remainder > 0) { result[i]++; remainder--; } } return result; }}Complexity
Time
O(n + m) - The algorithm involves a single pass over the `rolls` array to calculate its sum (O(m)) and another pass to construct the result array of size `n` (O(n)).
Space
O(n) or O(1) - We need O(n) space to store and return the result array. If the output array is not considered part of the space complexity, the algorithm uses O(1) extra space.
Trade-offs
Pros
Extremely efficient with linear time complexity, making it suitable for large constraints.
Simple and deterministic, directly calculating the solution without any searching.
Provides one valid solution out of potentially many, satisfying the problem requirements.
Cons
The logic relies on a mathematical insight, which might not be immediately obvious.
Requires careful handling of edge cases and integer arithmetic to avoid off-by-one errors.
Solutions
Solution
class Solution {public int[] missingRolls(int[] rolls, int mean, int n) { int m = rolls.length; int s = (n + m) * mean; for (int v : rolls) { s -= v; } if (s > n * 6 || s < n) { return new int[0]; } int[] ans = new int[n]; Arrays.fill(ans, s / n); for (int i = 0; i < s % n; ++i) { ++ans[i]; } return ans; }}class Solution {public: vector<int> missingRolls(vector<int> &rolls, int mean, int n) { int m = rolls.size(); int s = (n + m) * mean; for (int &v : rolls) s -= v; if (s > n * 6 || s < n) return {}; vector<int> ans(n, s / n); for (int i = 0; i < s % n; ++i) ++ans[i]; return ans; }};class Solution: def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]: m = len(rolls) s = (n + m) * mean - sum(rolls) if s > n * 6 or s < n: return [] ans = [s // n] * n for i in range(s % n): ans[i] += 1 return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.