Bit Manipulation
Master this topic with zero to advance depth.
Bit Manipulation: The Power of Binary
Bit manipulation involves algorithmically manipulating bits (0s and 1s). It is highly efficient and forms the basis of many hardware-level optimizations.
1. Essential Bitwise Operators
| Operator | Symbol | Rule |
|---|---|---|
| AND | & | 1 & 1 = 1, otherwise 0. (Masking) |
| OR | ` | ` |
| XOR | ^ | 1 ^ 0 = 1, 1 ^ 1 = 0. (Toggling/Canceling) |
| NOT | ~ | Flips all bits. |
| Left Shift | << | |
| Right Shift | >> | (Arithmetic) |
2. Common Bitwise Patterns
- Clear Rightmost Set Bit:
n & (n - 1)removes the least significant bit that is 1. - Extract Rightmost Set Bit:
n & -nisolates the lowest bit set to 1. - XOR Property: and . This is the basis for many "Single Number" problems.
3. Mental Model: Bitmasks
Think of a number as a collection of toggles. Bit manipulation allows you to flip, check, or set these toggles in time.
Single Number
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Examples
Level I: Brute Force (Frequency Map)
Intuition
Count the frequency of each number using a hash map. The number with frequency 1 is the answer.
Level II: Sorting
Intuition
By sorting the array, identical elements become adjacent. We can then iterate through the array in steps of 2. If an element is not equal to its successor, it's the single number.
Level III: Optimal (XOR Manipulation)
Intuition
The XOR operator has two key properties: and . Since every number except one appears twice, XORing all elements together will cause the duplicates to cancel out, leaving only the single number.
Power of Two
Given an integer n, return true if it is a power of two. Otherwise, return false.
An integer n is a power of two if there exists an integer x such that .
Examples
Level I: Brute Force (Division)
Intuition
Keep dividing the number by 2 until it hits 1. If at any point the remainder is not 0, it's not a power of two.
Level II: Math (Max Power of Two)
Intuition
Since the input is a 32-bit signed integer, the largest power of two is . If n is a power of two, it must be a divisor of .
Level III: Optimal (Bit Manipulation)
Intuition
A power of two in binary has exactly one bit set. The expression n & (n - 1) clears the rightmost set bit. If n is a power of two, clearing its only set bit should result in 0.
Single Number II
Given an integer array nums where every element appears three times except for one, which appears exactly once. Find the single element and return it.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Examples
Level I: Brute Force (Frequency Map)
Intuition
The simplest way to track occurrences is using a hash map or frequency array. We count how many times each number appears and return the one with a count of 1.
Level II: Sorting
Intuition
If we sort the numbers, identical numbers will be adjacent. We can jump in steps of 3 and check if nums[i] is different from nums[i+1].
Level III: Optimal (Bit Manipulation)
Intuition
Every number that appears three times will contribute exactly 3 (or 0) to the sum of bits at any given position. If we sum the bits at each position and take modulo 3, the remaining bit belongs to the single number.
Single Number III
Given an integer array nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once. You can return the answer in any order.
You must write an algorithm that runs in linear runtime complexity and uses only constant extra space.
Examples
Level I: Brute Force (Frequency Map)
Intuition
The most intuitive approach is to use a hash map to count the frequency of each number and extract those with a count of 1.
Level II: Sorting
Intuition
Sort the array to bring duplicates together. Iterate through the array; if current element is not equal to the next, it's a single number. Otherwise, skip two.
Level III: Optimal (Bitwise Partitioning)
Intuition
XORing all numbers gives . Find the lowest set bit in this XOR sum to divide all numbers into two groups (where this bit is set vs. not set). XORing within each group isolates and .
Bitwise AND of Numbers Range
Given two integers left and right that represent the range [left, right], return the bitwise AND of all numbers in this range, inclusive.
Examples
Level I: Brute Force (Linear AND)
Intuition
Iterate from left to right and perform bitwise AND on all numbers. This is slow if the range is large.
Thought Process
- Initialize
res = left. - Iterate
ifromleft + 1toright. res &= i.- Return
res.
Pattern: Simulation
Level II: Iterative Shift (Pre-calculation)
Intuition
Shift both left and right rightward until they are identical. The bits that are removed are the ones that fluctuate within the range. Finally, shift the common prefix back to its original position.
Level III: Optimal (Common Prefix / Brian Kernighan)
Intuition
The bitwise AND of a range is the common prefix of the binary representations of the range's endpoints. Any bit that changes within the range will eventually become 0 in the final AND result.
Thought Process
- While
right > left:right = right & (right - 1)(clears the rightmost set bit).
- Alternatively, shift both numbers right until they are equal, then shift back.
Pattern: Bitwise Prefix Match
Detailed Dry Run
left=5(101), right=7(111) Iteration 1: right = 7 & 6 = 6 (110). 6 > 5. Iteration 2: right = 6 & 5 = 4 (100). 4 < 5. Stop. Result: 4
Number of 1 Bits
Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight).
Examples
11 in binary is 1011, which has three '1' bits.
Level I: Brute Force (Iterate all 32 bits)
Intuition
The most straightforward way is to check each of the 32 bits one by one. We can do this by shifting the number right and checking the last bit using bitwise AND with 1.
Thought Process
- Initialize a counter
count = 0. - Loop 32 times (for a 32-bit integer):
- Check if the last bit is 1:
(n & 1) == 1. - If yes, increment
count. - Right shift by 1:
n >>= 1.
- Check if the last bit is 1:
- Return
count.
Pattern: Bitwise Iteration
Level II: Standard Library / Built-in
Intuition
Most modern programming languages provide highly optimized built-in functions to count set bits, often utilizing specific CPU instructions like POPCNT.
Level III: Optimal (Brian Kernighan's Algorithm)
Intuition
Instead of checking every bit, we can jump directly between set bits. The operation n & (n - 1) always clears the least significant set bit of .
Thought Process
- While :
- Set n = n \text{ & } (n - 1). This removes exactly one '1' bit.
- Increment
count.
- The number of iterations equals the number of set bits, which is more efficient for sparse numbers.
Pattern: Bit Manipulation Magic
Detailed Dry Run
n = 12 (binary 1100)
| Iteration | n (Before) | n-1 | n & (n-1) | count |
|---|---|---|---|---|
| 1 | 1100 (12) | 1011 (11) | 1000 (8) | 1 |
| 2 | 1000 (8) | 0111 (7) | 0000 (0) | 2 |
| Result: 2 |
Reverse Bits
Reverse bits of a given 32 bits unsigned integer.
Examples
43261596 (00000010100101000001111010011100) reversed is 964176192 (00111001011110000010100101000000).
Level I: Brute Force (Iterate and Shift)
Intuition
Iterate through each of the 32 bits of the input. In each step, shift the result left and add the last bit of the input. Then shift the input right.
Thought Process
- Initialize
res = 0. - Loop 32 times:
- Check the last bit of
n:n & 1. - Shift
resleft and add that bit:(res << 1) + (n & 1). - Right shift
nby 1.
- Check the last bit of
- Return
res.
Pattern: Bitwise Result Construction
Level II: Byte-by-Byte Lookup (Caching)
Intuition
A 32-bit integer consists of 4 bytes. We can precompute or manually reverse the bits for each byte (8 bits) and then combine them. This is faster when multiple calls are made as the byte reversals can be cached.
Level III: Optimal (Divide and Conquer)
Intuition
We can reverse the bits using a series of mask and shift operations. First, swap adjacent bits, then swap adjacent pairs, then adjacent nibbles (4 bits), and so on.
Thought Process
- Swap bits 1-by-1:
n = ((n & 0xAAAAAAAA) >>> 1) | ((n & 0x55555555) << 1) - Swap bits 2-by-2:
n = ((n & 0xCCCCCCCC) >>> 2) | ((n & 0x33333333) << 2) - Swap bits 4-by-4:
n = ((n & 0xF0F0F0F0) >>> 4) | ((n & 0x0F0F0F0F) << 4) - Swap bits 8-by-8:
n = ((n & 0xFF00FF00) >>> 8) | ((n & 0x00FF00FF) << 8) - Swap bits 16-by-16:
n = (n >>> 16) | (n << 16)
Pattern: Parallel Bit Processing
Sum of Two Integers
Given two integers a and b, return the sum of the two integers without using the operators + and -.
Examples
Level I: Brute Force (Bit-by-Bit Simulation)
Intuition
Simulate how a half-adder or full-adder works. Iterate through each bit position (0 to 31), calculate the sum of bits and the carry, and build the result bit by bit.
Thought Process
- Initialize
res = 0,carry = 0. - For
ifrom 0 to 31:- Get -th bits of
aandb. sum = bitA ^ bitB ^ carry.carry = (bitA & bitB) | (carry & (bitA ^ bitB)).- Set -th bit of
restosum.
- Get -th bits of
- Return
res.
Pattern: Simulation / Logic Gates
Level II: Recursive XOR & AND
Intuition
The iterative logic can be expressed recursively. The sum of a and b is equivalent to the XOR of a and b (sum without carry) plus the AND of a and b shifted left (the carry).
Level III: Optimal (Iterative XOR & AND)
Intuition
Addition can be broken into two parts: the sum without carry (a ^ b) and the carry itself ((a & b) << 1). We repeat this process until the carry becomes zero.
Thought Process
a ^ bgives the sum bits where no carry is involved.a & bgives the bits where a carry is generated.- Shift the carry left by 1 to add it to the next significant bit.
- Repeat until carry is 0.
Pattern: Recursive Addition Logic
Detailed Dry Run
a = 2 (10), b = 3 (11)
- Iteration 1: sum = 10 ^ 11 = 01 (1) carry = (10 & 11) << 1 = 100 (4)
- Iteration 2: sum = 001 ^ 100 = 101 (5) carry = (001 & 100) << 1 = 000 (0) Result: 5
Missing Number
Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array.
Examples
n = 3. Range is [0,3]. 2 is missing.
n = 2. Range is [0,2]. 2 is missing.
Level I: Brute Force (Sorting)
Intuition
Sort the array and check if each index matches the value at that index. The first index where nums[i] != i is the missing number. If all match, the missing number is .
Thought Process
- Sort
numsin ascending order. - Iterate from to :
- If
nums[i] != i, returni.
- If
- If loop finishes, return
n.
Pattern: Sorting
Level II: Math (Sum Formula)
Intuition
The sum of the first numbers is . By subtracting the sum of all elements in the array from this total sum, we obtain the missing number.
Level III: Optimal (XOR)
Intuition
XORing a number with itself results in 0 (). If we XOR all numbers in the range and all numbers in the array, every number present in the array will appear twice and cancel out, leaving only the missing number.
Thought Process
- Initialize
missing = n(or 0). - Iterate through the array:
missing ^= i ^ nums[i]
- Return
missing.
Pattern: XOR Cancellation
Detailed Dry Run
nums = [3, 0, 1], n = 3 missing = 3 i=0: missing = 3 ^ 0 ^ 3 = 0 i=1: missing = 0 ^ 1 ^ 0 = 1 i=2: missing = 1 ^ 2 ^ 1 = 2 Result: 2
Count Triplets That Can Form Two Arrays of Equal XOR
Given an array of integers arr. We want to select three indices i, j and k where (0 <= i < j <= k < arr.length).
Let a = arr[i] ^ ... ^ arr[j - 1] and b = arr[j] ^ ... ^ arr[k]. Return the number of triplets (i, j, k) such that a == b.
Examples
Level I: Brute Force (O(N^3))
Intuition
Iterate through all possible combinations of i, j, and k. Calculate a and b for each triplet and check if they are equal.
Thought Process
- Use three nested loops for
i,j, andk. - In the innermost loop, calculate XOR for
aandb. - If
a == b, incrementcount.
Pattern: Triple Nested Iteration
Level II: Prefix XOR with Hash Map
Intuition
We seek such that . Instead of a nested loop, we can use a hash map to store the indices (or counts and sum of indices) where each prefix XOR has occurred.
Level III: Optimal (Prefix XOR)
Intuition
As shown in the logic representation, is equivalent to . Using prefix XOR array where , the XOR of is . We need . If found, all are valid.
Thought Process
- Calculate prefix XOR array
prefix. - Iterate through all pairs where :
- If
prefix[i] == prefix[k+1]:- The number of valid
j's isk - i. - Add
k - itototal.
- The number of valid
- If
Pattern: Subarray XOR Frequency
Detailed Dry Run
arr = [2, 3, 1, 6, 7] Prefix: [0, 2, 1, 0, 6, 1] Pairs with equal prefix values:
- P[0] and P[3]: (i=0, k=2). count += 2-0 = 2 triplets.
- P[2] and P[5]: (i=2, k=4). count += 4-2 = 2 triplets. Total: 2 + 2 = 4.
Gray Code
An n-bit gray code sequence is a sequence of integers where:
- Every integer is in the inclusive range ,
- The first integer is 0,
- An integer appears no more than once in the sequence,
- The binary representation of every pair of adjacent integers differs by exactly one bit,
- The binary representation of the first and last integers differs by exactly one bit.
Given an integer n, return any valid n-bit gray code sequence.
Examples
00, 01, 11, 10 is a valid Gray code sequence.
Level I: Brute Force (Backtracking)
Intuition
Generate the sequence by exploring all possible next numbers that differ by exactly one bit. Maintain a visited set to ensure uniqueness.
Thought Process
- Start with 0.
- Try flipping each of the bits.
- If the result is not visited, move to it and recurse.
- If all bits visited, return the sequence.
Pattern: State Space Search
Level II: Reflected Construction (Iterative)
Intuition
Gray code for bits can be built from the Gray code for bits by reflecting the sequence and adding a leading 1 (bit ) to the reflected part.
Level III: Optimal (Bit Manipulation Formula)
Intuition
The -th number in the Gray code sequence can be generated using the formula . This formula ensures that adjacent numbers differ by exactly one bit because shifting and XORing cancels out bits that change in a ripple carry but leaves the most significant changing bit.
Thought Process
- The total number of elements is .
- For each index from 0 to :
- Calculate
i ^ (i >> 1).
- Calculate
- Add to result list and return.
Pattern: Formula-based Generation
Detailed Dry Run
n = 2
- i=0: 0 ^ (0>>1) = 0 ^ 0 = 0 (00)
- i=1: 1 ^ (1>>1) = 1 ^ 0 = 1 (01)
- i=2: 2 ^ (2>>1) = 2 ^ 1 = 3 (11)
- i=3: 3 ^ (3>>1) = 3 ^ 1 = 2 (10) Result: [0, 1, 3, 2]
Repeated DNA Sequences
Given a string s that represents a DNA sequence, return all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.
Examples
Level I: Brute Force (Hash Set of Strings)
Intuition
Iterate through every possible 10-letter substring and store it in a hash set. If we encounter a substring that is already in the set, we add it to our result list.
Thought Process
- Use a
seenhash set to track substrings. - Use a
repeatedhash set to collect result strings. - Loop
ifrom 0 tos.length() - 10:- Extract substring
s.substring(i, i + 10). - If in
seen, add torepeated. - Else, add to
seen.
- Extract substring
Pattern: String Rolling Window
Level II: Rolling Hash (Rabin-Karp)
Intuition
Instead of re-extracting substrings, we treat each 10-letter window as a number in base 4 (since there are 4 DNA bases). As we slide the window, we update the hash in time.
Level III: Optimal (Bitmasking)
Intuition
Since there are only 4 characters, map them to 2 bits. A 10-char sequence is a 20-bit integer. Use a sliding window to update the bitmask in per character.
Thought Process
- Map A=0, C=1, G=2, T=3.
- Maintain a 20-bit sliding window.
- Use a hash map/set to track encountered bitmasks.
Pattern: 2-bit Character Encoding
Maximum Product of Word Lengths
Given a string array words, return the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. If no such two words exist, return 0.
Examples
Level I: Brute Force (Check All Pairs)
Intuition
Iterate through every pair of words and check if they have common characters using a helper function.
Thought Process
- Nested loop for all pairs.
- For each pair:
- Check overlap: For char in word[i], is it in word[j]?
- If no overlap, update
maxProd.
Pattern: Double Iteration
Level II: Precomputed Sets
Intuition
For each word, precompute a set of its characters. When comparing two words, check if their character sets have any intersection. This is faster than a raw character-by-character check but slower than bitmasking.
Level III: Optimal (Bitmasking)
Intuition
Each word can be represented by a 26-bit integer (bitmask). Two words share NO common letters if and only if their bitwise AND is 0.
Thought Process
- Precompute bitmasks for all words.
- Nested loop and check
(masks[i] & masks[j]) == 0. - Update max product.
Pattern: Alphabet Bitmasking
Detailed Dry Run
"abcw" -> mask = 0x400007 "xtfn" -> mask = 0x882020 mask1 & mask2 = 0. Product = 4 * 4 = 16.
Maximum XOR of Two Numbers in an Array
Given an integer array nums, return the maximum result of nums[i] XOR nums[j], where .
Examples
Level I: Brute Force (All Pairs)
Intuition
Check every possible pair of numbers and calculate their XOR sum. Track the maximum value found.
Thought Process
- Initialize
maxResult = 0. - Nested loop through
nums. maxResult = max(maxResult, nums[i] ^ nums[j]).- Return
maxResult.
Pattern: Double Iteration
Level II: Greedy Comparison with Hash Set
Intuition
We can build the maximum XOR bit by bit. For each bit position (from MSB to LSB), we check if there exists a pair of numbers whose -th bits could potentially form a better maximum XOR than what we have found so far.
Level III: Optimal (Binary Trie)
Intuition
To maximize XOR, for each number , we want to find another number such that they have different bits at the highest possible positions. A Trie (Prefix Tree) storing binary representations allows us to greedily find the bitwise opposite at each step.
Thought Process
- Insert all numbers into a Trie of depth 31.
- For each number :
- Start at the Trie root.
- For each bit of (from MSB to LSB):
- If we want bit and it exists in the Trie, move there and add to our current XOR.
- Else, move to the child with bit .
- Track the best XOR found for any .
Pattern: Bitwise Greedy with Trie
Divide Two Integers
Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator.
Examples
10/3 = 3.33333... which is truncated to 3.
7/-3 = -2.33333... which is truncated to -2.
Level I: Brute Force (Linear Subtraction)
Intuition
Keep subtracting the divisor from the dividend until the dividend becomes smaller than the divisor. The number of times we subtract is the quotient.
Thought Process
- Handle edge cases (overflow for
INT_MIN). - Determine sign of result.
- Take absolute values of
dividendanddivisor. - Loop while
dividend >= divisor:dividend -= divisor.count++.
- Apply sign and return.
Pattern: Simulation
Level II: Recursive Long Division
Intuition
The exponential subtraction can be performed recursively. In each call, we find the largest multiple of the divisor that can be subtracted and then recurse on the remainder.
Level III: Optimal (Exponential Subtraction / Shifts)
Intuition
Instead of subtracting exactly one divisor at a time, we subtract the largest possible multiple of the divisor using bit shifts (divisor << k). This is equivalent to long division in binary.
Thought Process
- While
dividend >= divisor:- Find the largest such that
divisor << k <= dividend. dividend -= (divisor << k).quotient += (1 << k).
- Find the largest such that
- This uses the property that is a fast way to find large chunks to subtract.
Pattern: Exponential Backoff / Long Division
Detailed Dry Run
15 / 3
- Largest shift: 3 << 2 = 12. 15 - 12 = 3. Quotient = 4 (2^2).
- Largest shift: 3 << 0 = 3. 3 - 3 = 0. Quotient = 4 + 1 = 5. Result: 5
Total Hamming Distance
The Hamming distance between two integers is the number of positions at which the corresponding bits are different. Return the sum of Hamming distances between all pairs of integers in nums.
Examples
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
Level I: Brute Force (Check All Pairs)
Intuition
The most direct way is to iterate through every pair in the array, calculate their Hamming distance, and sum them up.
Thought Process
- Initialize
totalDist = 0. - For each pair where :
- Calculate Hamming distance:
Integer.bitCount(nums[i] ^ nums[j]). - Add to
totalDist.
- Calculate Hamming distance:
- Return
totalDist.
Pattern: Nested Iteration
Level II: Iterative Bit Verification
Intuition
We can calculate the Hamming distance for each pair by iterating through the numbers and checking each bit. This is similar to the brute force but slightly more structured.
Level III: Optimal (Bit Counting per Position)
Intuition
Instead of checking pairs, we can check bit positions. For any bit position , if numbers have the -th bit set to 1, and numbers have it set to 0, then there are pairs that differ at this position.
Thought Process
- Initialize
total = 0. - For each bit position to :
- Count numbers with -th bit set.
total += k * (n - k).
- Return
total.
Pattern: Positional Counting
Detailed Dry Run
nums: [4, 14, 2], n=3 Bit Pos 1: Bits are {0, 1, 0}. k=1, n-k=2. Pairs = 12 = 2. Bit Pos 2: Bits are {1, 1, 0}. k=2, n-k=1. Pairs = 21 = 2. Bit Pos 3: Bits are {0, 1, 0}. k=1, n-k=2. Pairs = 1*2 = 2. Total: 2+2+2 = 6.
Minimum Flips to Make a OR b Equal to c
Given 3 positives a, b and c. Return the minimum flips required in some bits of a and b to make (a OR b == c).
Examples
Level I: Brute Force (Bit-by-Bit Check)
Intuition
Iterate through each bit of the three numbers and compare the required state c with the current state a | b. Count the flips needed for each bit position.
Thought Process
- For each bit position (0 to 31):
- If -th bit of
cis 0:- Both -th bits of
aandbmust be 0. Add their sum toflips.
- Both -th bits of
- If -th bit of
cis 1:- At least one of -th bits of
aorbmust be 1. If both are 0, add 1 toflips.
- At least one of -th bits of
- If -th bit of
- Return
flips.
Pattern: Positional Verification
Level II: Iterative with Built-in Counting
Intuition
Instead of checking every bit manually, we can use built-in bit counting functions to calculate the flips needed for the entire numbers after identifying which bits are incorrect via XOR and AND.
Level III: Optimal (Bitwise Magic)
Intuition
We can use bitwise operators to find all differing bits at once. (a | b) ^ c gives bits that are incorrect. We then handle the cases where c bit is 0 separately as they might require 2 flips per bit.
Thought Process
incorrect = (a | b) ^ c.must_flip_two = a & b & incorrect.- Flips = Count of set bits in
incorrect+ Count of set bits inmust_flip_two.
Pattern: Composite Bitmasking
Detailed Dry Run
a=2(0010), b=6(0110), c=5(0101) a|b = 6 (0110) incorrect = 0110 ^ 0101 = 0011 (bits 0 and 1 are wrong) must_flip_two = 0010 & 0110 & 0011 = 0010 (bit 1 is wrong and both a,b are 1) Total = popcount(0011) + popcount(0010) = 2 + 1 = 3.
Sum of All Subset XOR Totals
Return the sum of all XOR totals for every subset of nums.
Examples
Level I: Brute Force (Backtracking)
Intuition
Generate all possible subsets, calculate the XOR of each, and sum them up.
Thought Process
- Use recursion to explore including or excluding each element.
- Maintain a
currentXorvalue through the recursion tree. - Base case: If reached end of array, return
currentXor.
Pattern: Subset Generation
Level II: Iterative Subset Generation
Intuition
Use a bitmask from 0 to to represent every possible subset of nums. For each mask, calculate the XOR total and add it to the sum.
Level III: Optimal (Contribution of Each Bit)
Intuition
For a bit position , if at least one number in nums has the -th bit set, then in exactly half of the subsets (i.e., ), the XOR total will have the -th bit set. This is because adding a number with the -th bit set flips the -th bit of the XOR sum.
Thought Process
- Find the bitwise OR of all numbers in the array. This identifies all bit positions that are set in at least one number.
- If the -th bit is set in the OR result, it contributes to the total sum.
- Result =
(OR of all nums) * 2^(n-1).
Pattern: Combinatorial Bit Counting
Detailed Dry Run
nums = [1, 3], n = 2 OR = 1 | 3 = 3 (binary 11) Sum = 3 * 2^(2-1) = 3 * 2 = 6. Result matches brute force!
Reverse Pairs
Given an integer array nums, return the number of reverse pairs in the array. A reverse pair is a pair such that and .
Examples
Level I: Brute Force (Nested Loops)
Intuition
Check every possible pair where . If the condition is met, increment the counter.
Thought Process
- Use a nested loop .
- Check if .
- Return count.
Pattern: All-Pairs Comparison
Level II: Merge Sort based Counting
Intuition
Similar to counting inversions, we can use merge sort to count reverse pairs. During the merge step, for each element in the left half, we find how many elements in the right half satisfy .
Level III: Optimal (Binary Indexed Tree / Fenwick Tree)
Intuition
As we iterate through the array, we want to count how many numbers seen so far are greater than . A Binary Indexed Tree (BIT) can efficiently handle point updates and prefix sums. Since values can be large, we use coordinate compression on all and .
Thought Process
- Collect all and and sort them to create distinct ranks (Coordinate Compression).
- Iterate through
numsfrom right to left (or left to right with adjustments):- Query BIT for how many elements are strictly less than .
- Update BIT with .
- This leverages the bitwise structure of indices in the BIT.
Pattern: BIT with Coordinate Compression
Can I Win
Two players take turns choosing integers from 1 to maxChoosableInteger without reuse. The first to reach desiredTotal wins. Return true if the first player can force a win.
Examples
Level I: Recursive Minimax (No Memoization)
Intuition
Explore all possible sequences of choosing numbers. A player wins if they can pick a number that reaches the total, or if there is a number they can pick such that the other player cannot win from the resulting state.
Thought Process
- Try choosing each available number .
- If , you win.
- Otherwise, if the other player cannot win from the state (remainder - , used numbers), you win.
- If no such exists, you lose.
Pattern: Game Theory Recursion
Level II: Recursion with Bitmask only
Intuition
Represent the state of used numbers with a 20-bit integer mask. This is more efficient for passing state through recursion but still suffers from exponential growth without memoization.
Level III: Optimal (Bitmask DP / Memoization)
Intuition
The state of the game is uniquely determined by which integers have been used. Since maxChoosableInteger is at most 20, we can use a bitmask of length 20 to represent the set of used numbers. Memoizing the results of these masks drastically reduces the number of computations.
Thought Process
- Use an integer
maskwhere the -th bit is 1 if number is used. - Store result of
canWin(mask)in a hash map or array. - Base cases:
desiredTotal <= 0or sum check.
Pattern: State Compression DP
Maximum AND Sum of Array
Place n integers into numSlots slots (max 2 per slot). The AND sum is the sum of (nums[i] & slotNumber). Return the maximum possible AND sum.
Examples
Level I: Brute Force (Recursion)
Intuition
Try all possible placements of the integers into the slots. Each slot can take up to 2 integers. This is an exhaustive search of the solution space.
Level II: Greedy / Simple DP
Intuition
Identify that the problem has overlapping subproblems. Even without a full ternary mask, we can use a simpler memoization based on the current counts array (converted to a string or tuple) to avoid redundant work.
Level III: Bitmask DP (Ternary / Base-3)
Intuition
Since each slot can hold up to 2 integers, we can represent the state of the slots using a base-3 integer. In this integer, the -th digit (in base 3) represents the number of elements in slot (0, 1, or 2).
Thought Process
- Use a recursive function
solve(index, mask)whereindexis the current number innumswe are placing. - The
maskis a base-3 representation of slot occupancies. - For each slot :
- Check if slot has items.
- If yes, place
nums[index]in slot , update mask, and take the results.
Pattern: Base-N Bitmasking
Found an issue or have a suggestion?
Help us improve! Report bugs or suggest new features on our Telegram group.