Facebook Pixel

2419. Longest Subarray With Maximum Bitwise AND

MediumBit ManipulationBrainteaserArray
Leetcode Link

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 of nums
  • 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 integers a and b
  • 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 just a itself
  • For a two-element subarray [a, b], the bitwise AND is a & b, which is at most min(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 than 5)

Therefore, the problem reduces to finding the longest consecutive sequence of the maximum value in the array. We just need to:

  1. Find the maximum value in the array
  2. 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 values
  • ans: the longest length found so far

The algorithm works as follows:

  1. Initialize ans = 0 and cnt = 0
  2. For each element x in nums:
    • If x equals the maximum value mx:
      • Increment cnt by 1 (extending the current consecutive sequence)
      • Update ans to be the maximum of ans and cnt
    • Otherwise:
      • Reset cnt to 0 (the consecutive sequence is broken)
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 Evaluator

Example 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:

IndexElementActioncntans
01Not max, reset cnt00
12Not max, reset cnt00
23Equals max, increment cnt11
33Equals max, increment cnt22
42Not max, reset cnt02
52Not max, reset cnt02
63Equals max, increment cnt12
73Equals max, increment cnt22
83Equals max, increment cnt33
91Not max, reset cnt03

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) takes O(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 return 1
  • All same elements [7, 7, 7, 7] should return 4
  • Array with no consecutive max values [1, 3, 2, 3, 1] should return 1

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
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which two pointer techniques do you use to check if a string is a palindrome?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More