3344. Maximum Sized Array 🔒
Problem Description
You are given a positive integer s
. You need to create a 3D array A
with dimensions n × n × n
, where each element is calculated using a specific formula.
For each element in the array, A[i][j][k]
is defined as:
A[i][j][k] = i * (j OR k)
, where0 <= i, j, k < n
- The
OR
operation is the bitwise OR operation
Your task is to find the maximum possible value of n
such that when you sum up all elements in the entire 3D array A
, the total sum does not exceed s
.
For example, if n = 2
, you would have a 2×2×2 array with 8 elements total:
A[0][0][0] = 0 * (0 OR 0) = 0
A[0][0][1] = 0 * (0 OR 1) = 0
A[0][1][0] = 0 * (1 OR 0) = 0
A[0][1][1] = 0 * (1 OR 1) = 0
A[1][0][0] = 1 * (0 OR 0) = 0
A[1][0][1] = 1 * (0 OR 1) = 1
A[1][1][0] = 1 * (1 OR 0) = 1
A[1][1][1] = 1 * (1 OR 1) = 1
The sum would be 3, and if s >= 3
, then n = 2
would be valid. You need to find the largest such n
where the sum stays within the limit s
.
Intuition
Let's think about how to calculate the sum efficiently. If we expand the sum of all elements in the 3D array:
Sum = Σ(i=0 to n-1) Σ(j=0 to n-1) Σ(k=0 to n-1) i * (j OR k)
We can rearrange this as:
Sum = Σ(i=0 to n-1) i * Σ(j=0 to n-1) Σ(k=0 to n-1) (j OR k)
Notice that the inner double summation Σ(j=0 to n-1) Σ(k=0 to n-1) (j OR k)
is independent of i
. Let's call this value S_or
.
The key insight is that for any fixed value of j OR k
, we can count how many (j, k)
pairs produce that value. Due to symmetry in the OR operation, we can simplify our calculation.
For efficiency, we can precompute f[n]
which represents Σ(i=0 to n-1) Σ(j=0 to i) (i OR j)
. Why up to i
instead of n-1
? Because (i OR j)
where j <= i
captures the essential pattern, and we can use symmetry to handle the full range.
The total sum for a given n
can then be expressed as:
Total Sum = f[n-1] * (n-1) * n / 2
This formula accounts for the multiplication by each i
value and the proper counting of all (j, k)
pairs.
Since the sum grows rapidly with n
(approximately as n^5
), and we want the maximum n
where the sum doesn't exceed s
, binary search becomes the natural choice. We can estimate that n
won't exceed around 1330 based on the growth rate.
By preprocessing the values up to this maximum and then using binary search, we can efficiently find the largest valid n
where the total sum stays within the limit s
.
Learn more about Binary Search patterns.
Solution Approach
The solution consists of two main parts: preprocessing and binary search.
Preprocessing Phase:
First, we establish an upper bound for n
. Since the sum grows approximately as (n-1)^5 / 4
, and we need (n-1)^5 / 4 ≤ s
, we can determine that n
won't exceed approximately 1330 for reasonable values of s
.
We precompute an array f
where f[i]
represents the sum Σ(j=0 to i) Σ(k=0 to j) (j OR k)
. The preprocessing code:
mx = 1330
f = [0] * mx
for i in range(1, mx):
f[i] = f[i - 1] + i # Add the case where j OR k = i (when j = k = i)
for j in range(i):
f[i] += 2 * (i | j) # Count both (i, j) and (j, i) cases
The formula f[i] = f[i-1] + i + 2 * Σ(j=0 to i-1) (i OR j)
builds upon the previous value and adds new contributions from index i
.
Binary Search Phase:
Once we have the preprocessed values, we use binary search to find the maximum n
such that the total sum doesn't exceed s
.
For a given n
, the total sum of the 3D array is calculated as:
Total Sum = f[n-1] * (n-1) * n / 2
This formula accounts for:
f[n-1]
: The sum pattern for OR operations(n-1)
: Multiplication by each value ofi
from 0 to n-1n / 2
: Proper scaling factor for the 3D array structure
The binary search implementation:
def maxSizedArray(self, s: int) -> int:
l, r = 1, mx
while l < r:
m = (l + r + 1) >> 1 # Middle point, biased towards upper half
if f[m - 1] * (m - 1) * m // 2 <= s:
l = m # Sum is within limit, try larger n
else:
r = m - 1 # Sum exceeds limit, try smaller n
return l
The binary search finds the largest n
where the total sum remains ≤ s
. The expression (l + r + 1) >> 1
ensures we round up when calculating the midpoint, preventing infinite loops when l
and r
are adjacent values.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through finding the maximum n
for s = 10
.
Step 1: Understanding the 3D Array
For n = 2
, we calculate all elements:
- When
i = 0
: All elements are 0 (since0 * anything = 0
) - When
i = 1
:A[1][0][0] = 1 * (0 OR 0) = 1 * 0 = 0
A[1][0][1] = 1 * (0 OR 1) = 1 * 1 = 1
A[1][1][0] = 1 * (1 OR 0) = 1 * 1 = 1
A[1][1][1] = 1 * (1 OR 1) = 1 * 1 = 1
Total sum = 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 = 3
Step 2: Preprocessing Values
We build our f
array:
f[0] = 0
f[1] = f[0] + 1 + 2*(1 OR 0) = 0 + 1 + 2*1 = 3
f[2] = f[1] + 2 + 2*(2 OR 0) + 2*(2 OR 1) = 3 + 2 + 2*2 + 2*3 = 3 + 2 + 4 + 6 = 15
Step 3: Binary Search
Now we search for maximum n
where the sum ≤ 10:
Initial range: l = 1, r = 1330
First iteration:
m = (1 + 1330 + 1) / 2 = 666
- Calculate sum for
n = 666
: This would be enormous, much greater than 10 - Update:
r = 665
After several iterations, we narrow down to:
- When checking
n = 2
: Sum =f[1] * 1 * 2 / 2 = 3 * 1 * 1 = 3
✓ (≤ 10) - When checking
n = 3
: Sum =f[2] * 2 * 3 / 2 = 15 * 2 * 3 / 2 = 45
✗ (> 10)
Therefore, the maximum n = 2
.
Verification:
For n = 2
, the total sum is 3, which is indeed ≤ 10. For n = 3
, we would have a 3×3×3 array where the sum would be 45, exceeding our limit. Thus, n = 2
is the correct answer.
Solution Implementation
1# Maximum array size to precompute
2MAX_SIZE = 1330
3
4# Precompute cumulative OR sums for all array sizes
5# cumulative_or_sum[i] = sum of all (j | k) for 0 <= j, k < i
6cumulative_or_sum = [0] * MAX_SIZE
7
8for array_size in range(1, MAX_SIZE):
9 # Start with previous cumulative sum
10 cumulative_or_sum[array_size] = cumulative_or_sum[array_size - 1] + array_size
11
12 # Add contribution of OR operations with the new element (array_size)
13 for element in range(array_size):
14 cumulative_or_sum[array_size] += 2 * (array_size | element)
15
16
17class Solution:
18 def maxSizedArray(self, s: int) -> int:
19 """
20 Find the maximum array size where the total cost doesn't exceed s.
21
22 The cost for an array of size n is calculated as:
23 cumulative_or_sum[n-1] * (n-1) * n // 2
24
25 Args:
26 s: Maximum allowed cost
27
28 Returns:
29 Maximum array size that satisfies the cost constraint
30 """
31 left, right = 1, MAX_SIZE
32
33 # Binary search for the maximum valid array size
34 while left < right:
35 # Calculate middle point (ceiling division)
36 mid = (left + right + 1) >> 1
37
38 # Check if array of size 'mid' satisfies the cost constraint
39 cost = cumulative_or_sum[mid - 1] * (mid - 1) * mid // 2
40
41 if cost <= s:
42 # Cost is within limit, try larger sizes
43 left = mid
44 else:
45 # Cost exceeds limit, try smaller sizes
46 right = mid - 1
47
48 return left
49
1class Solution {
2 // Maximum array size to precompute
3 private static final int MAX_SIZE = 1330;
4
5 // Precomputed values for each array size
6 // f[i] represents the sum: i + 2 * sum of (i | j) for all j from 0 to i-1
7 private static final long[] precomputedValues = new long[MAX_SIZE];
8
9 // Static initialization block to precompute values
10 static {
11 for (int i = 1; i < MAX_SIZE; ++i) {
12 // Start with the previous computed value plus current index
13 precomputedValues[i] = precomputedValues[i - 1] + i;
14
15 // Add twice the bitwise OR of current index with all previous indices
16 for (int j = 0; j < i; ++j) {
17 precomputedValues[i] += 2 * (i | j);
18 }
19 }
20 }
21
22 public int maxSizedArray(long s) {
23 // Binary search boundaries
24 int left = 1;
25 int right = MAX_SIZE;
26
27 // Binary search to find the maximum valid array size
28 while (left < right) {
29 // Calculate middle point (using bit shift for division by 2)
30 // Adding 1 before shifting ensures we round up
31 int mid = (left + right + 1) >> 1;
32
33 // Check if the computed value for size (mid-1) satisfies the constraint
34 // The formula multiplies precomputed value by (mid-1) * mid / 2
35 if (precomputedValues[mid - 1] * (mid - 1) * mid / 2 <= s) {
36 // If condition holds, search in the upper half
37 left = mid;
38 } else {
39 // Otherwise, search in the lower half
40 right = mid - 1;
41 }
42 }
43
44 // Return the maximum array size that satisfies the constraint
45 return left;
46 }
47}
48
1// Maximum array size constant
2const int MAX_SIZE = 1330;
3
4// Precomputed values for array size calculations
5// f[i] represents the sum of i plus all pairwise OR operations for elements 0 to i-1
6long long cumulativeOrSum[MAX_SIZE];
7
8// Initialize the precomputed values at compile time
9auto initializer = [] {
10 cumulativeOrSum[0] = 0;
11
12 for (int i = 1; i < MAX_SIZE; ++i) {
13 // Start with the sum from previous iteration plus current index
14 cumulativeOrSum[i] = cumulativeOrSum[i - 1] + i;
15
16 // Add twice the bitwise OR of current index with all previous indices
17 // (twice because each pair contributes to both elements)
18 for (int j = 0; j < i; ++j) {
19 cumulativeOrSum[i] += 2 * (i | j);
20 }
21 }
22 return 0;
23}();
24
25class Solution {
26public:
27 /**
28 * Finds the maximum size of an array that satisfies the given constraint.
29 * Uses binary search to find the largest valid array size.
30 *
31 * @param s The upper bound constraint value
32 * @return The maximum size of the array that satisfies the constraint
33 */
34 int maxSizedArray(long long s) {
35 int left = 1;
36 int right = MAX_SIZE;
37
38 // Binary search for the maximum valid array size
39 while (left < right) {
40 // Calculate middle point (ceiling division to avoid infinite loop)
41 int mid = (left + right + 1) >> 1;
42
43 // Check if array of size 'mid' satisfies the constraint
44 // The formula calculates: f[mid-1] * (mid-1) * mid / 2
45 if (cumulativeOrSum[mid - 1] * (mid - 1) * mid / 2 <= s) {
46 // Valid size, try to find a larger one
47 left = mid;
48 } else {
49 // Size too large, search in smaller range
50 right = mid - 1;
51 }
52 }
53
54 return left;
55 }
56};
57
1// Maximum array size constant
2const MAX_SIZE = 1330;
3
4// Precomputed values array for optimization
5// f[i] represents the cumulative sum for size i
6const precomputedValues: bigint[] = Array(MAX_SIZE).fill(0n);
7
8// Initialize precomputed values using IIFE (Immediately Invoked Function Expression)
9(() => {
10 // Base case: empty array has sum 0
11 precomputedValues[0] = 0n;
12
13 // Calculate cumulative sums for each array size
14 for (let i = 1; i < MAX_SIZE; i++) {
15 // Start with previous sum plus current index
16 precomputedValues[i] = precomputedValues[i - 1] + BigInt(i);
17
18 // Add contribution from bitwise OR operations with all previous indices
19 for (let j = 0; j < i; j++) {
20 // Each OR operation contributes twice (for both i|j and j|i pairs)
21 precomputedValues[i] += BigInt(2) * BigInt(i | j);
22 }
23 }
24})();
25
26/**
27 * Finds the maximum sized array whose total sum does not exceed the given limit
28 * Uses binary search to find the largest valid array size
29 *
30 * @param s - The maximum allowed sum
31 * @returns The maximum array size that satisfies the sum constraint
32 */
33function maxSizedArray(s: number): number {
34 // Binary search boundaries
35 let left = 1;
36 let right = MAX_SIZE;
37 const targetSum = BigInt(s);
38
39 // Binary search for the maximum valid array size
40 while (left < right) {
41 // Calculate middle point (ceiling division for upper bound)
42 const mid = (left + right + 1) >> 1;
43
44 // Calculate the total sum for an array of size mid
45 // Formula: (precomputedValues[mid-1] * (mid-1) * mid) / 2
46 const currentSum = (precomputedValues[mid - 1] * BigInt(mid - 1) * BigInt(mid)) / BigInt(2);
47
48 if (currentSum <= targetSum) {
49 // Current size is valid, try larger sizes
50 left = mid;
51 } else {
52 // Current size exceeds limit, try smaller sizes
53 right = mid - 1;
54 }
55 }
56
57 return left;
58}
59
Time and Space Complexity
The time complexity consists of two parts:
-
Preprocessing phase: The outer loop runs from
1
tomx-1
(i.e.,O(mx)
iterations). For each iterationi
, the inner loop runsi
times, performing a bitwise OR operation and arithmetic operations. This results in1 + 2 + 3 + ... + (mx-1) = (mx-1) * mx / 2
operations, giving usO(mx^2)
time complexity for preprocessing. -
Binary search phase: The
maxSizedArray
method performs a binary search between1
andmx
. Each iteration of the while loop reduces the search space by half, resulting inO(log mx)
time complexity.
Therefore, the total time complexity is O(mx^2 + log mx)
. Since mx = 1330
is a constant, we can also express this as O(n^2 + log n)
where n
represents the upper bound of the search range.
The space complexity is O(mx)
or O(n)
, as we allocate an array f
of size mx
to store the precomputed values. No additional space that scales with input is used during the binary search phase.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow in Cost Calculation
Pitfall: The most critical issue in this solution is potential integer overflow when calculating the cost:
cost = cumulative_or_sum[mid - 1] * (mid - 1) * mid // 2
For large values of mid
(approaching 1330), the multiplication cumulative_or_sum[mid - 1] * (mid - 1) * mid
can exceed Python's integer limits in other languages or cause performance issues even in Python with very large numbers.
Solution: Rearrange the calculation to perform division earlier or check for overflow:
# Option 1: Divide earlier to reduce intermediate values cost = cumulative_or_sum[mid - 1] * ((mid - 1) * mid // 2) # Option 2: Check if multiplication would exceed s before computing if cumulative_or_sum[mid - 1] > s * 2 // ((mid - 1) * mid): right = mid - 1 continue
2. Off-by-One Error in Binary Search
Pitfall: The binary search uses (left + right + 1) >> 1
for the midpoint calculation. If you accidentally use (left + right) >> 1
instead, the binary search may enter an infinite loop when left = right - 1
and the condition holds true for mid = left
.
Solution: Always use ceiling division when the update rule is left = mid
:
mid = (left + right + 1) >> 1 # Correct: ceiling division # NOT: mid = (left + right) >> 1 # Wrong: can cause infinite loop
3. Incorrect Precomputation Formula
Pitfall: The precomputation loop might be implemented incorrectly:
# Wrong: Missing the factor of 2 for symmetric pairs
for array_size in range(1, MAX_SIZE):
cumulative_or_sum[array_size] = cumulative_or_sum[array_size - 1] + array_size
for element in range(array_size):
cumulative_or_sum[array_size] += (array_size | element) # Missing factor of 2!
This misses that for each unique OR value, we need to count both (j, k) and (k, j) pairs when j ≠k.
Solution: Ensure the factor of 2 is included for non-diagonal elements:
for array_size in range(1, MAX_SIZE):
cumulative_or_sum[array_size] = cumulative_or_sum[array_size - 1] + array_size
for element in range(array_size):
cumulative_or_sum[array_size] += 2 * (array_size | element) # Correct
4. Hardcoded Maximum Size Without Validation
Pitfall: Using a fixed MAX_SIZE = 1330
without considering the actual input range. If s
is extremely large (beyond what 1330 can handle), the solution would return an incorrect answer.
Solution: Dynamically determine the upper bound based on s
:
def maxSizedArray(self, s: int) -> int:
# Dynamically calculate upper bound
# Since sum ~ n^5/4, we have n ~ (4*s)^(1/5)
import math
max_possible = min(MAX_SIZE, int((4 * s) ** 0.2) + 10) # Add buffer
left, right = 1, max_possible
# ... rest of binary search
5. Not Handling Edge Cases
Pitfall: Not properly handling small values of s
:
- When
s = 0
, the answer should be 1 (array of size 1 has sum 0) - When
s < 0
, the input is invalid
Solution: Add edge case handling:
def maxSizedArray(self, s: int) -> int:
if s == 0:
return 1
if s < 0:
raise ValueError("s must be non-negative")
# Continue with normal binary search...
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!