Find the Number of Copy Arrays
MedPrompt
You are given an array original of length n and a 2D array bounds of length n x 2, where bounds[i] = [ui, vi].
You need to find the number of possible arrays copy of length n such that:
(copy[i] - copy[i - 1]) == (original[i] - original[i - 1])for1 <= i <= n - 1.ui <= copy[i] <= vifor0 <= i <= n - 1.
Return the number of such arrays.
Example 1:
Input: original = [1,2,3,4], bounds = [[1,2],[2,3],[3,4],[4,5]]
Output: 2
Explanation:
The possible arrays are:
[1, 2, 3, 4][2, 3, 4, 5]
Example 2:
Input: original = [1,2,3,4], bounds = [[1,10],[2,9],[3,8],[4,7]]
Output: 4
Explanation:
The possible arrays are:
[1, 2, 3, 4][2, 3, 4, 5][3, 4, 5, 6][4, 5, 6, 7]
Example 3:
Input: original = [1,2,1,2], bounds = [[1,1],[2,3],[3,3],[2,3]]
Output: 0
Explanation:
No array is possible.
Constraints:
2 <= n == original.length <= 1051 <= original[i] <= 109bounds.length == nbounds[i].length == 21 <= bounds[i][0] <= bounds[i][1] <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
This approach is a straightforward brute-force method. It first recognizes the key property that the copy array is a shifted version of the original array, i.e., copy[i] = original[i] + d for some constant d. It then determines an initial search range for d based on the constraints of the first element. Finally, it iterates through every possible integer value of d in this range and, for each one, verifies if it satisfies the constraints for all other elements in the array. The number of d values that pass this check is the answer.
Algorithm
- The first condition
copy[i] - copy[i - 1] == original[i] - original[i - 1]implies thatcopy[i] - original[i]is a constant for alli. Let this constant bed. Thus,copy[i] = original[i] + dfor alli. - The problem is now to find the number of valid integer values for
d. - A brute-force approach can be to determine a possible range for
dand then test each value. - We can use the bounds for the first element (
i=0) to establish an initial range ford. Frombounds[0][0] <= copy[0] <= bounds[0][1], we getbounds[0][0] <= original[0] + d <= bounds[0][1], which meansdmust be in the range[bounds[0][0] - original[0], bounds[0][1] - original[0]]. - We can iterate through every integer
din this initial range. - For each
d, we check if it's valid for all other elements fromi = 1ton-1. A valuedis valid ifbounds[i][0] <= original[i] + d <= bounds[i][1]holds for alli. - We count the number of such valid
dvalues.
Walkthrough
The algorithm proceeds as follows:
- Calculate the initial range for the difference
dusing the bounds fororiginal[0]. Let this range be[d_min, d_max], whered_min = bounds[0][0] - original[0]andd_max = bounds[0][1] - original[0]. - Initialize a counter for valid arrays to zero.
- Loop through each integer
dfromd_mintod_max. - Inside the loop, for each
d, assume it's valid and check against the constraints fori = 1ton-1. - A nested loop checks if
original[i] + dis within[bounds[i][0], bounds[i][1]]. - If
dis valid for alli, increment the counter. - After the outer loop finishes, the counter holds the total number of possible
copyarrays.
class Solution { public long numberOfCopyArrays(int[] original, int[][] bounds) { long count = 0; // Using long for d to be safe, though the initial range might be small. long d_min = (long)bounds[0][0] - original[0]; long d_max = (long)bounds[0][1] - original[0]; for (long d = d_min; d <= d_max; d++) { boolean isValid = true; // Check this d for all other elements for (int i = 1; i < original.length; i++) { long copy_i = (long)original[i] + d; if (copy_i < bounds[i][0] || copy_i > bounds[i][1]) { isValid = false; break; } } if (isValid) { count++; } } return count; }}Complexity
Time
O((V₀ - U₀) * n) - where `n` is the length of the array, and `V₀` and `U₀` are the upper and lower bounds for the first element. The outer loop runs `V₀ - U₀ + 1` times, and the inner loop runs `n-1` times. This is highly inefficient if the range `V₀ - U₀` is large.
Space
O(1) - We only use a few variables to store the loop counter and state, regardless of the input size.
Trade-offs
Pros
Conceptually simple and easy to implement.
Correctly models the problem's constraints.
Cons
The time complexity is dependent on the range of values in
bounds[0], which can be very large (up to 10^9).This approach will result in a 'Time Limit Exceeded' error for most test cases due to its inefficiency.
This optimal approach is based on a key mathematical insight. By rearranging the first condition, we can deduce that any valid copy array must be a simple translation of the original array, i.e., copy[i] = original[i] + d for some constant difference d. The problem then becomes finding the number of possible integer values for d.
Each element's bounds [u_i, v_i] impose a constraint on d of the form u_i - original[i] <= d <= v_i - original[i]. To satisfy all constraints simultaneously, d must fall within the intersection of all these individual ranges. By finding the maximum of all lower bounds and the minimum of all upper bounds for d, we can determine the final valid range for d in a single pass through the input arrays. The size of this final range gives the answer.
Algorithm
- The first condition
copy[i] - copy[i - 1] == original[i] - original[i - 1]can be rewritten ascopy[i] - original[i] == copy[i - 1] - original[i - 1]. This shows that the differencecopy[i] - original[i]is a constant for alli. Let's call this constant differenced. - Therefore,
copy[i] = original[i] + dfor allifrom0ton-1. - The problem reduces to finding the number of possible integer values for
d. - The second condition is
bounds[i][0] <= copy[i] <= bounds[i][1]. Substitutingcopy[i], we getbounds[i][0] <= original[i] + d <= bounds[i][1]. - Rearranging for
d, we get an inequality for eachi:bounds[i][0] - original[i] <= d <= bounds[i][1] - original[i]. - To satisfy all
nconditions simultaneously,dmust lie in the intersection of all thesenranges. - The intersection of a set of intervals
[l_i, r_i]is given by[max(l_i), min(r_i)]. - We can find the overall tightest lower bound (
maxLowerBound) and upper bound (minUpperBound) fordby iterating through the arrays once. - Initialize
maxLowerBoundto a very small number (e.g.,Long.MIN_VALUE) andminUpperBoundto a very large number (e.g.,Long.MAX_VALUE). - Iterate from
i = 0ton-1, updatingmaxLowerBound = max(maxLowerBound, bounds[i][0] - original[i])andminUpperBound = min(minUpperBound, bounds[i][1] - original[i]). - After the loop, if
maxLowerBound > minUpperBound, there is no validd, so the number of arrays is 0. - Otherwise, the number of possible integer values for
disminUpperBound - maxLowerBound + 1.
Walkthrough
The algorithm is as follows:
- Establish that
copy[i] = original[i] + dfor a constantd. - For each
i, this impliesbounds[i][0] - original[i] <= d <= bounds[i][1] - original[i]. - We need to find the intersection of these
nranges ford. The intersection will be a single range[max_lower, min_upper]. - Initialize
maxLowerBound = Long.MIN_VALUEandminUpperBound = Long.MAX_VALUE. - Iterate through the arrays from
i = 0ton-1. - In each iteration, calculate the lower and upper bound for
dfor the currenti:lower_d = bounds[i][0] - original[i]andupper_d = bounds[i][1] - original[i]. - Update the overall tightest bounds:
maxLowerBound = Math.max(maxLowerBound, lower_d)andminUpperBound = Math.min(minUpperBound, upper_d). - After the loop, check if a valid range exists. If
maxLowerBound > minUpperBound, no integerdcan satisfy all conditions, so return 0. - Otherwise, the number of valid integers for
dis the length of the range, which isminUpperBound - maxLowerBound + 1.
class Solution { public long numberOfCopyArrays(int[] original, int[][] bounds) { long maxLowerBound = Long.MIN_VALUE; long minUpperBound = Long.MAX_VALUE; for (int i = 0; i < original.length; i++) { // Calculate the allowed range for the difference 'd' for the current element long lower_d = (long)bounds[i][0] - original[i]; long upper_d = (long)bounds[i][1] - original[i]; // Narrow down the global valid range for 'd' by intersecting with the current range maxLowerBound = Math.max(maxLowerBound, lower_d); minUpperBound = Math.min(minUpperBound, upper_d); } // If the max lower bound is greater than the min upper bound, the intersection is empty if (maxLowerBound > minUpperBound) { return 0; } // The number of possible integer values for 'd' is the size of the final range return minUpperBound - maxLowerBound + 1; }}Complexity
Time
O(n) - The algorithm involves a single pass through the input arrays of length `n` to find the intersection of the ranges.
Space
O(1) - The algorithm only requires a few variables to store the maximum lower bound and minimum upper bound, independent of the input size.
Trade-offs
Pros
Extremely efficient with linear time complexity.
Handles all constraints, including large values and ranges.
Uses constant extra space.
Cons
Requires a mathematical insight to transform the problem into a range intersection problem, which might not be immediately obvious.
Video 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.