2419. Longest Subarray With Maximum Bitwise AND
Problem Description
You are given an integer array nums
of size n
.
The problem asks you to find the longest subarray that has the maximum possible bitwise AND value.
Here's what this means:
- First, find the maximum bitwise AND value
k
that can be obtained from any subarray ofnums
- Then, among all subarrays that have this maximum bitwise AND value
k
, find the length of the longest one
Key points to understand:
- A subarray is a contiguous sequence of elements from the array (elements must be adjacent in the original array)
- The bitwise AND of an array is the result of applying the AND operation to all numbers in that array
- You need to return just the length of the longest subarray that achieves the maximum bitwise AND
For example, if nums = [1, 2, 3, 3, 2, 2]
and the maximum bitwise AND of any subarray is 3
, you would look for the longest contiguous sequence that gives this value of 3
when all elements are ANDed together.
The key insight here is that the bitwise AND operation between numbers never increases the result - it either stays the same or decreases. This means the maximum possible bitwise AND value from any subarray is actually just the maximum single element in the array itself (a subarray of length 1). Therefore, the problem simplifies to finding the longest consecutive sequence of the maximum value in the array.
Intuition
The key observation is understanding how the bitwise AND operation behaves. When we perform AND between two numbers, each bit in the result can only be 1
if both corresponding bits in the input numbers are 1
. This means:
a & b ≤ min(a, b)
for any positive integersa
andb
- The AND operation can only maintain or reduce the value, never increase it
Given this property, what's the maximum possible bitwise AND we can get from any subarray?
Let's think about it:
- For a single element subarray
[a]
, the bitwise AND is justa
itself - For a two-element subarray
[a, b]
, the bitwise AND isa & b
, which is at mostmin(a, b)
- For longer subarrays, adding more elements can only maintain or further reduce the AND result
This leads us to realize that the maximum bitwise AND value achievable from any subarray is simply the maximum element in the entire array. This maximum can only be achieved by a subarray containing just that maximum element, or consecutive maximum elements.
For example, if max(nums) = 5
:
- A subarray
[5]
has bitwise AND =5
- A subarray
[5, 5]
has bitwise AND =5 & 5 = 5
- A subarray
[5, 5, 5]
has bitwise AND =5 & 5 & 5 = 5
- But a subarray
[5, 3]
has bitwise AND =5 & 3 = 1
(which is less than5
)
Therefore, the problem reduces to finding the longest consecutive sequence of the maximum value in the array. We just need to:
- Find the maximum value in the array
- Find the longest consecutive run of this maximum value
Solution Approach
Based on our intuition, the solution becomes straightforward with a two-pass approach:
Step 1: Find the maximum value First, we traverse the array to find the maximum element:
mx = max(nums)
Step 2: Find the longest consecutive sequence of the maximum value We then traverse the array again, keeping track of:
cnt
: the current length of consecutive maximum valuesans
: the longest length found so far
The algorithm works as follows:
- Initialize
ans = 0
andcnt = 0
- For each element
x
innums
:- If
x
equals the maximum valuemx
:- Increment
cnt
by 1 (extending the current consecutive sequence) - Update
ans
to be the maximum ofans
andcnt
- Increment
- Otherwise:
- Reset
cnt
to 0 (the consecutive sequence is broken)
- Reset
- If
ans = cnt = 0
for x in nums:
if x == mx:
cnt += 1
ans = max(ans, cnt)
else:
cnt = 0
return ans
Time Complexity: O(n)
where n
is the length of the array
- First pass to find maximum:
O(n)
- Second pass to find longest sequence:
O(n)
Space Complexity: O(1)
- we only use a constant amount of extra space for variables mx
, ans
, and cnt
The beauty of this solution lies in transforming what seems like a complex bitwise operation problem into a simple pattern-finding problem by understanding the fundamental property of the AND operation.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [1, 2, 3, 3, 2, 2, 3, 3, 3, 1]
.
Step 1: Find the maximum value
- Traverse the array:
[1, 2, 3, 3, 2, 2, 3, 3, 3, 1]
- Maximum value
mx = 3
Step 2: Find the longest consecutive sequence of maximum value (3)
Initialize: ans = 0
, cnt = 0
Now let's process each element:
Index | Element | Action | cnt | ans |
---|---|---|---|---|
0 | 1 | Not max, reset cnt | 0 | 0 |
1 | 2 | Not max, reset cnt | 0 | 0 |
2 | 3 | Equals max, increment cnt | 1 | 1 |
3 | 3 | Equals max, increment cnt | 2 | 2 |
4 | 2 | Not max, reset cnt | 0 | 2 |
5 | 2 | Not max, reset cnt | 0 | 2 |
6 | 3 | Equals max, increment cnt | 1 | 2 |
7 | 3 | Equals max, increment cnt | 2 | 2 |
8 | 3 | Equals max, increment cnt | 3 | 3 |
9 | 1 | Not max, reset cnt | 0 | 3 |
Result: The longest consecutive sequence of the maximum value (3) has length 3.
This corresponds to the subarray [3, 3, 3]
at indices 6-8, which has bitwise AND = 3 & 3 & 3 = 3
.
We can verify this is indeed the maximum bitwise AND:
- Any subarray containing non-3 elements will have AND < 3
- Subarrays of only 3's maintain AND = 3
- The longest such subarray has length 3
Solution Implementation
1class Solution:
2 def longestSubarray(self, nums: List[int]) -> int:
3 # Find the maximum value in the array
4 max_value = max(nums)
5
6 # Initialize variables to track the longest subarray and current count
7 longest_length = 0
8 current_count = 0
9
10 # Iterate through each element in the array
11 for num in nums:
12 if num == max_value:
13 # If current element equals max value, increment the counter
14 current_count += 1
15 # Update the longest length if current count is greater
16 longest_length = max(longest_length, current_count)
17 else:
18 # Reset counter when element is not equal to max value
19 current_count = 0
20
21 return longest_length
22
1class Solution {
2 public int longestSubarray(int[] nums) {
3 // Find the maximum value in the array
4 int maxValue = Arrays.stream(nums).max().getAsInt();
5
6 // Track the longest subarray length and current consecutive count
7 int longestLength = 0;
8 int currentCount = 0;
9
10 // Iterate through each element in the array
11 for (int currentNum : nums) {
12 // If current element equals the maximum value, increment count
13 if (currentNum == maxValue) {
14 currentCount++;
15 // Update the longest length if current count is greater
16 longestLength = Math.max(longestLength, currentCount);
17 } else {
18 // Reset count when element is not the maximum value
19 currentCount = 0;
20 }
21 }
22
23 return longestLength;
24 }
25}
26
1class Solution {
2public:
3 int longestSubarray(vector<int>& nums) {
4 // Find the maximum value in the array
5 int maxValue = *max_element(nums.begin(), nums.end());
6
7 // Initialize variables to track the longest subarray length and current count
8 int longestLength = 0;
9 int currentCount = 0;
10
11 // Iterate through each element in the array
12 for (int num : nums) {
13 if (num == maxValue) {
14 // If current element equals max value, increment the current count
15 currentCount++;
16 // Update the longest length if current count is greater
17 longestLength = max(longestLength, currentCount);
18 } else {
19 // Reset count if current element is not the max value
20 currentCount = 0;
21 }
22 }
23
24 return longestLength;
25 }
26};
27
1/**
2 * Finds the length of the longest contiguous subarray where all elements equal the maximum value
3 * @param nums - Array of numbers to process
4 * @returns The length of the longest subarray containing only the maximum value
5 */
6function longestSubarray(nums: number[]): number {
7 // Find the maximum value in the array
8 const maxValue: number = Math.max(...nums);
9
10 // Initialize variables to track the longest streak and current streak
11 let longestStreak: number = 0;
12 let currentStreak: number = 0;
13
14 // Iterate through each number in the array
15 for (const currentNumber of nums) {
16 if (currentNumber === maxValue) {
17 // If current number equals max, increment the current streak
18 currentStreak++;
19 // Update longest streak if current streak is longer
20 longestStreak = Math.max(longestStreak, currentStreak);
21 } else {
22 // Reset current streak if number doesn't equal max
23 currentStreak = 0;
24 }
25 }
26
27 return longestStreak;
28}
29
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. This is because:
- Finding the maximum element using
max(nums)
takesO(n)
time as it needs to traverse the entire array once - The for loop iterates through all
n
elements exactly once, performing constant time operations (O(1)
) for each element (comparison, increment, and max update) - Total time:
O(n) + O(n) = O(n)
The space complexity is O(1)
. The algorithm only uses a constant amount of extra space:
mx
stores the maximum value (single integer)ans
stores the final answer (single integer)cnt
stores the current count (single integer)x
is the loop variable (single integer)
No additional data structures that grow with input size are used, so the space complexity remains constant.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Misunderstanding the Problem - Trying to Calculate AND for All Subarrays
The Mistake: Many people initially approach this problem by trying to calculate the bitwise AND for every possible subarray, which leads to inefficient solutions:
# WRONG APPROACH - Time Limit Exceeded
def longestSubarray(self, nums: List[int]) -> int:
n = len(nums)
max_and = 0
result = 0
# Check all possible subarrays - O(n²) or O(n³)
for i in range(n):
for j in range(i, n):
# Calculate AND for subarray [i, j]
current_and = nums[i]
for k in range(i + 1, j + 1):
current_and &= nums[k]
if current_and > max_and:
max_and = current_and
result = j - i + 1
elif current_and == max_and:
result = max(result, j - i + 1)
return result
Why It's Wrong:
- This approach has O(n³) time complexity, which is extremely inefficient
- It fails to recognize the key property that AND operations can only decrease or maintain values, never increase them
The Fix: Recognize that the maximum AND value achievable is simply the maximum element in the array (when taking a subarray of length 1). The problem then reduces to finding the longest consecutive sequence of this maximum value.
Pitfall 2: Forgetting to Reset the Counter
The Mistake:
# WRONG - Counter never resets
def longestSubarray(self, nums: List[int]) -> int:
max_value = max(nums)
longest_length = 0
current_count = 0
for num in nums:
if num == max_value:
current_count += 1
longest_length = max(longest_length, current_count)
# Missing else clause to reset current_count!
return longest_length
Why It's Wrong:
Without resetting current_count
when encountering a non-maximum element, the counter continues to accumulate across disconnected sequences. For example, with nums = [3, 1, 3, 3]
, this would incorrectly return 3 instead of 2.
The Fix: Always reset the counter to 0 when the current element is not equal to the maximum value:
else: current_count = 0
Pitfall 3: Edge Case - Empty Array or Single Element
The Mistake: Not handling edge cases properly, especially when the array has only one element or when all elements are the same:
# Potentially problematic if not careful
def longestSubarray(self, nums: List[int]) -> int:
if not nums: # What if nums is empty?
return 0
max_value = max(nums)
# ... rest of the code
Why It Matters: While the provided solution handles single-element arrays correctly (it would return 1), it's important to verify that edge cases work:
- Single element array
[5]
should return1
- All same elements
[7, 7, 7, 7]
should return4
- Array with no consecutive max values
[1, 3, 2, 3, 1]
should return1
The Fix: The original solution already handles these cases correctly, but it's crucial to test them:
# Test cases to verify: assert longestSubarray([5]) == 1 assert longestSubarray([7, 7, 7, 7]) == 4 assert longestSubarray([1, 3, 2, 3, 1]) == 1
Which two pointer techniques do you use to check if a string is a palindrome?
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!