{x}
blog image

Longest Nice Subarray

You are given an array nums consisting of positive integers.

We call a subarray of nums nice if the bitwise AND of every pair of elements that are in different positions in the subarray is equal to 0.

Return the length of the longest nice subarray.

A subarray is a contiguous part of an array.

Note that subarrays of length 1 are always considered nice.

 

Example 1:

Input: nums = [1,3,8,48,10]
Output: 3
Explanation: The longest nice subarray is [3,8,48]. This subarray satisfies the conditions:
- 3 AND 8 = 0.
- 3 AND 48 = 0.
- 8 AND 48 = 0.
It can be proven that no longer nice subarray can be obtained, so we return 3.

Example 2:

Input: nums = [3,1,5,11,13]
Output: 1
Explanation: The length of the longest nice subarray is 1. Any subarray of length 1 can be chosen.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109

Solution Explanation: Longest Nice Subarray

The problem asks to find the longest subarray where the bitwise AND of any two distinct elements is 0. This means that no two numbers in the subarray share a set bit (a bit with value 1) in the same position.

Approach: The optimal approach uses a sliding window and bit manipulation. We maintain a mask variable that keeps track of the bitwise OR of all numbers currently within the window. If we encounter a new number whose bitwise AND with the current mask is non-zero, it means that this new number shares a set bit with at least one number already in the window, violating the "nice" subarray condition. Therefore, we shrink the window from the left until the condition is satisfied again.

Algorithm:

  1. Initialization:

    • ans: Stores the length of the longest nice subarray found so far (initialized to 0).
    • mask: Stores the bitwise OR of numbers in the current window (initialized to 0).
    • l: Left pointer of the sliding window (initialized to 0).
    • r: Right pointer of the sliding window (initialized to 0).
  2. Iteration: The code iterates through the nums array using the right pointer r.

  3. Window Adjustment: For each new element nums[r], it checks if mask & nums[r] is non-zero. If it is, it means the condition is violated. The while loop shrinks the window from the left by XORing nums[l] with mask and incrementing l until the condition mask & nums[r] == 0 becomes true. This effectively removes elements from the left of the window that are causing the conflict.

  4. Update Mask and Answer: After the while loop (or if the condition was already true), the new element nums[r] is added to the mask using bitwise OR (mask |= nums[r]). The length of the current window (r - l + 1) is compared with the current maximum length (ans), and ans is updated if necessary.

  5. Return: After iterating through all elements, the function returns ans.

Time Complexity: O(N), where N is the length of the input array. In the worst case, each element might be added to and removed from the window once. The while loop inside the main loop can potentially run up to N times in total.

Space Complexity: O(1). The algorithm uses only a few constant extra variables.

Code in Different Languages:

The code provided in the original response demonstrates the solution in several languages. Here's a summary of the common structure:

def longestNiceSubarray(nums):
    ans = mask = l = 0
    for r, x in enumerate(nums):
        while mask & x:
            mask ^= nums[l]
            l += 1
        mask |= x
        ans = max(ans, r - l + 1)
    return ans

The code in Java, C++, Go, TypeScript, Rust, and C# follows a very similar structure, with only minor syntax differences to accommodate the specific language features. The core logic remains identical across all implementations.