Problem Description
Given an integer array nums and two integers low and high, return the number of nice pairs. A nice pair (i, j) must satisfy 0 <= i < j < nums.length and low <= (nums[i] XOR nums[j]) <= high.
Key Insights
- The brute-force solution would check every pair in O(n^2), which is too slow when n can be 20000.
- Use a trie (bitwise tree) to store numbers seen so far. This allows us to count how many numbers yield an XOR value below a given limit when XORed with the current number.
- To count pairs with XOR in the range [low, high], compute countPairs(high) - countPairs(low - 1) where countPairs(limit) finds the number of pairs with XOR less than or equal to limit.
- Each number is processed bit-by-bit (up to around 15 bits, since nums[i] and limits are up to 20000) so the per-number work is constant.
Space and Time Complexity
Time Complexity: O(n * B) where B is the number of bits (approximately 15), essentially O(n).
Space Complexity: O(n * B) for the trie storage, which is acceptable for the given constraints.
Solution
We use a bitwise trie to store binary representations of previously seen numbers. For each number in the array, we count how many previously inserted numbers yield an XOR value with this number less than or equal to a certain limit (first high and then low-1). The count difference gives us the number of pairs within the desired range. The trie nodes store a count of how many numbers pass through that node (for the corresponding bit 0 or 1). When searching for the count of numbers that satisfy the XOR condition, we compare bits of the current number and the limit and traverse the trie accordingly. This approach significantly reduces the time compared to comparing every pair.