Problem
|
|
Winston was given the above mysterious function func
. He has an integer array arr
and an integer target
and he wants to find the values l
and r
that make the value |func(arr, l, r) - target|
minimum possible.
Return the minimum possible value of |func(arr, l, r) - target|
.
Notice that func
should be called with the values l
and r
where 0 <= l, r < arr.length
.
Examples
Example 1:
|
|
Example 2:
|
|
Example 3:
|
|
Solution
Method 1 - Naive
We need a brute force approach with optimisations where feasible since there’s no direct formula for bitwise AND over subarrays:
- Iterate over all pairs of indices
(l, r)
(nested loops, (O(n^2))). - For each pair
(l, r)
, compute:- The bitwise AND of the subarray
arr[l:r+1]
usingfunc
. - Calculate the absolute difference (|func(arr, l, r) - target|).
- Track the minimum difference (
min_diff
).
- The bitwise AND of the subarray
- Return the minimum difference.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n^2)
due to nested loops - 🧺 Space complexity:
O(1)
Method 2 - Using Set
The key observation is that during the computation of the bitwise AND for subarrays, the number of distinct results decreases as the subarray length increases. For larger subarrays, many overlapping subarrays yield the same bitwise AND result, hence we can optimise the traversal by using a set to avoid redundant calculations.
-
For each starting index
l
:- Instead of redundantly evaluating all subarray AND results, maintain a set of distinct values of
ans
(bitwise AND values). - This reduces the number of bitwise AND operations per iteration of
r
.
- Instead of redundantly evaluating all subarray AND results, maintain a set of distinct values of
-
Every time a unique AND operation leads to a new value that has already been seen, stop further evaluation.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n^2)
due to nested loops again - 🧺 Space complexity:
O(n)
Method 3 - Sliding Window
To improve the time complexity of the problem, we need to minimise redundant computations while still maintaining a systematic approach to explore subarrays. Using a set reduces redundancy to some extent but doesn’t completely optimise the solution as the worst-case scenario is still (O(n^2)).
A more efficient way is to use a sliding window technique combined with incremental bitwise AND to avoid recalculating or revisiting subarrays entirely. Additionally, we can track all possible AND computations of overlapping intervals in each iteration to avoid full traversal.
Key Insights for Optimisation
-
Bitwise AND Properties:
- The AND operator is monotonically decreasing (i.e.,
x & y <= x
andx & y <= y
). This is helpful because once the result becomes smaller than thetarget
or repeats, we can stop further computations.
- The AND operator is monotonically decreasing (i.e.,
-
Tracking Unique AND Results in Sliding Window:
- Instead of creating subarrays from scratch, maintain the set of current AND results (
currSet
) from previous iterations and update them as we extend the subarray. This reduces redundant calculations significantly.
- Instead of creating subarrays from scratch, maintain the set of current AND results (
-
Exponential Decay of Unique AND Results:
- Since all numbers in a subarray are ANDed together, the number of distinct AND results degenerates quickly. For example:
- A larger subarray tends to have fewer unique AND results compared to smaller subarrays.
- This observation leads to the use of dynamic programming or efficient data structures to only explore distinct AND results.
- Since all numbers in a subarray are ANDed together, the number of distinct AND results degenerates quickly. For example:
Optimised Approach
We use the following improvement:
- Traverse the array with a single loop for the starting index
l
. - For each iteration:
- Track the results of the AND operations dynamically in a set.
- Update the set to hold AND results for overlapping subarrays when extending subarrays.
- At each set update:
- Compute the absolute difference with
target
. - Update the minimum difference (
min_diff
).
- Compute the absolute difference with
- If the AND operation yields a result smaller than
target
or repeats, break the inner loop early.
This reduces the computations drastically.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n*M)
where M islog(max(arr))
.- The total number of unique AND operations across all subarrays decays exponentially due to the monotonicity and repetition of results.
- Practically, this leads to an average case complexity of
O(n*M)
, whereM
describes the time needed to compute ANDs for distinct numbers.
- 🧺 Space complexity:
O(n)
for using the set