Bitwise AND visualization

2419: Longest Subarray With Maximum Bitwise AND

Difficulty: Medium
Topics: Bitwise Operations, Array Manipulation
Companies: Google, Amazon, Microsoft
Pro Tip: The maximum bitwise AND of any subarray is always equal to the maximum element in the array. The longest subarray with this value is the longest contiguous segment of the maximum element.

Problem Statement

Given an integer array nums, find the length of the longest contiguous subarray where the bitwise AND of the subarray equals the maximum possible bitwise AND of any subarray.

The bitwise AND of a subarray is the bitwise AND of all integers in that contiguous segment.

Example 1

Input: nums = [1,2,3,3,2,2]

Output: 2

Explanation: The maximum bitwise AND is 3. The longest contiguous subarray with bitwise AND 3 is [3,3] (length 2).

Example 2

Input: nums = [1,2,3,4]

Output: 1

Explanation: The maximum bitwise AND is 4. The only contiguous subarray with bitwise AND 4 is [4] (length 1).

Problem Link: View on LeetCode ↗

Key Insight

The solution relies on two crucial observations:

  1. The maximum possible bitwise AND of any subarray is equal to the maximum element in the array (max_val)
  2. The longest subarray with bitwise AND equal to max_val is the longest contiguous segment of max_val in the original array
3
3
2
1
3

The longest contiguous segment of max value (3) has length 2. We cannot connect non-adjacent 3's without breaking contiguity.

Important: While we can delete elements, the problem requires selecting a contiguous subarray from the remaining elements in their original order. We cannot reorder elements, only delete some.

Optimal Approach: Find Longest Contiguous Segment

This approach finds the longest contiguous segment of the maximum value in the original array.

Algorithm Steps

  1. Find the maximum value in the array
  2. Traverse the array to find the longest contiguous segment of this maximum value
  3. Return the length of this segment

Why This Works

The maximum bitwise AND value can only be achieved by subarrays consisting entirely of the maximum element. The longest such subarray is the longest contiguous segment of this value in the original array.

Complexity Analysis

Time Complexity Space Complexity
O(n) O(1)

Where n is the length of the array. We traverse the array once to find the maximum and once to find the longest segment.

Optimal Solution
class Solution {
public:
    int longestSubarray(vector<int>& nums) {
        // Find the maximum value
        int max_val = *max_element(nums.begin(), nums.end());
        int max_len = 0;
        int curr_len = 0;
        
        for (int num : nums) {
            if (num == max_val) {
                curr_len++;
                max_len = max(max_len, curr_len);
            } else {
                curr_len = 0;
            }
        }
        
        return max_len;
    }
};
class Solution {
    public int longestSubarray(int[] nums) {
        // Find the maximum value
        int max_val = Integer.MIN_VALUE;
        for (int num : nums) {
            if (num > max_val) max_val = num;
        }
        
        int max_len = 0;
        int curr_len = 0;
        for (int num : nums) {
            if (num == max_val) {
                curr_len++;
                max_len = Math.max(max_len, curr_len);
            } else {
                curr_len = 0;
            }
        }
        
        return max_len;
    }
}
class Solution:
    def longestSubarray(self, nums: List[int]) -> int:
        # Find the maximum value
        max_val = max(nums)
        max_len = curr_len = 0
        
        for num in nums:
            if num == max_val:
                curr_len += 1
                max_len = max(max_len, curr_len)
            else:
                curr_len = 0
                
        return max_len
Implementation Note: This approach efficiently finds the solution in O(n) time with O(1) space by leveraging a single pass after finding the maximum value.

Alternative Approach: Single Pass with Max Tracking

This approach combines finding the maximum value and tracking contiguous segments in a single pass.

Algorithm Steps

  1. Initialize variables for current maximum value, current segment length, and maximum segment length
  2. Traverse the array:
    • Update current segment length when encountering current maximum
    • Reset when encountering a new maximum or different value
    • Track the longest segment length
  3. Return the maximum segment length

Complexity Analysis

Time Complexity Space Complexity
O(n) O(1)

Slightly more efficient as it finds the maximum and longest segment in a single pass.

Single Pass Solution
class Solution {
public:
    int longestSubarray(vector<int>& nums) {
        int max_val = INT_MIN;
        int curr_len = 0;
        int max_len = 0;
        
        for (int num : nums) {
            if (num > max_val) {
                // New maximum found
                max_val = num;
                max_len = 1;
                curr_len = 1;
            } else if (num == max_val) {
                // Continue current segment
                curr_len++;
                max_len = max(max_len, curr_len);
            } else {
                // Reset current segment
                curr_len = 0;
            }
        }
        
        return max_len;
    }
};
class Solution {
    public int longestSubarray(int[] nums) {
        int max_val = Integer.MIN_VALUE;
        int curr_len = 0;
        int max_len = 0;
        
        for (int num : nums) {
            if (num > max_val) {
                max_val = num;
                max_len = 1;
                curr_len = 1;
            } else if (num == max_val) {
                curr_len++;
                max_len = Math.max(max_len, curr_len);
            } else {
                curr_len = 0;
            }
        }
        
        return max_len;
    }
}
class Solution:
    极客 longestSubarray(self, nums: List[int]) -> int:
        max_val = float('-inf')
        curr_len = 0
        max_len = 0
        
        for num in nums:
            if num > max_val:
                # New maximum found
                max_val = num
                max_len = 1
                curr_len = 1
            elif num == max_val:
                # Continue current segment
                curr_len += 1
                max_len = max(max_len, curr_len)
            else:
                # Reset current segment
                curr_len = 0
                
        return max_len
Implementation Note: This approach is slightly more efficient as it finds the maximum and tracks segments in a single pass. However, both approaches have the same time complexity.

Frequently Asked Questions

1. Why is the maximum bitwise AND equal to the maximum element?

For any two numbers, a & b ≤ min(a, b) ≤ max(a, b). Therefore, the bitwise AND of any subarray cannot exceed the maximum element in the array. The maximum element itself will have a bitwise AND equal to itself when taken alone.

2. Why can we delete elements arbitrarily?

The problem allows deleting any number of elements (as long as the array doesn't become empty). This means we can remove all non-maximum elements, making all maximum elements contiguous.

3. What if there are multiple maximum values?

All occurrences of the maximum value contribute to the solution. After deleting non-max elements, we can form a contiguous block of all maximum values.

4. Why not use the longest contiguous segment in the original array?

Because deletion allows us to connect non-adjacent maximum values. The problem doesn't require the subarray to be contiguous in the original array, only in the modified array after deletion.

5. How does bitwise AND work with multiple numbers?

Bitwise AND of multiple numbers only keeps the bits that are set in all numbers. If any number misses a bit that's set in the maximum value, the result will be less than the maximum.

6. What's the time complexity of the optimal solution?

O(n) since we traverse the array twice: once to find the maximum and once to count its frequency.

7. Can we solve this in a single pass?

Yes, we can find the maximum and count its frequency in a single pass, but it requires careful implementation to handle the maximum value updates correctly.

8. How large can the input array be?

According to constraints, the array length can be up to 10^5, so O(n) solutions are required.

9. What if the array has negative numbers?

The constraint states that nums[i] ≥ 1, so negative numbers are not possible.

10. Why is this problem marked as medium difficulty?

The key insight (that deletion allows connecting non-adjacent max values) is non-trivial. Many initially think about contiguous segments in the original array.

Final Insight: This problem teaches an important lesson in bitwise operations and array manipulation. By recognizing that deletion allows maximum flexibility, we arrive at an elegant O(n) solution that's both efficient and intuitive.