feat(content): bit manipulation pattern

This commit is contained in:
2025-09-08 14:46:22 +01:00
parent 6398b0eec8
commit 8333e1777f

View File

@@ -0,0 +1,229 @@
name: Bit Manipulation
slug: bit-manipulation
difficulty_level: 2
description: >
Techniques using binary operations (AND, OR, XOR, NOT, shifts) to solve
problems efficiently, often achieving O(1) space where other approaches
need O(n).
when_to_use: |
- Finding unique elements when pairs cancel out (XOR)
- Checking powers of 2 (n & (n-1) == 0)
- Counting set bits (Brian Kernighan's algorithm)
- Swapping without temp variable (a ^= b; b ^= a; a ^= b)
- Problems requiring O(1) extra space
- Toggling or flipping bits
metaphor: |
Think of XOR like a light switch. Flip it once (XOR with a number) and
the light turns on. Flip it again with the same number and it turns off.
Numbers that appear twice "flip twice" and cancel out, leaving only the
single number.
Another analogy: imagine each number is a musical note. Playing the same
note twice creates silence (destructive interference). When you play all
notes together, pairs cancel out, and only the unique note remains audible.
core_concept: |
Bit manipulation uses properties of binary operations to solve problems
elegantly. The most important operations:
**XOR (⊕):**
- `a ⊕ a = 0` — any number XORed with itself is zero
- `a ⊕ 0 = a` — XORing with zero preserves the value
- XOR is commutative and associative — order doesn't matter
**AND (&):**
- `a & (a-1)` removes the lowest set bit
- `a & 1` checks if a number is odd
**OR (|):**
- `a | (1 << k)` sets the k-th bit
**Shifts:**
- `a << k` multiplies by 2^k
- `a >> k` divides by 2^k (floor)
visualization: |
**XOR Cancellation Example:**
```
nums = [2, 2, 1]
Step 1: result = 0
0000 XOR 0010 = 0010 (result = 2)
Step 2: result = 2
0010 XOR 0010 = 0000 (pair cancels!)
Step 3: result = 0
0000 XOR 0001 = 0001 (result = 1)
Answer: 1 (the single number)
```
**Bit-by-bit XOR:**
```
0010 (2)
⊕ 0010 (2)
--------
0000 (0) — same bits cancel!
0000 (0)
⊕ 0001 (1)
--------
0001 (1) — XOR with 0 preserves
```
code_template: |
# XOR all elements - pairs cancel, unique remains
def find_single(nums: list[int]) -> int:
result = 0
for num in nums:
result ^= num
return result
# Check if n is a power of 2
def is_power_of_two(n: int) -> bool:
return n > 0 and (n & (n - 1)) == 0
# Count number of 1 bits (Brian Kernighan)
def count_bits(n: int) -> int:
count = 0
while n:
n &= (n - 1) # Remove lowest set bit
count += 1
return count
# Get k-th bit (0-indexed from right)
def get_bit(n: int, k: int) -> int:
return (n >> k) & 1
# Set k-th bit
def set_bit(n: int, k: int) -> int:
return n | (1 << k)
# Clear k-th bit
def clear_bit(n: int, k: int) -> int:
return n & ~(1 << k)
# Toggle k-th bit
def toggle_bit(n: int, k: int) -> int:
return n ^ (1 << k)
# Swap without temp (XOR swap)
def swap(a: int, b: int) -> tuple[int, int]:
a ^= b
b ^= a
a ^= b
return a, b
# Find two single numbers (all others appear twice)
def find_two_singles(nums: list[int]) -> list[int]:
# XOR all numbers - result is xor of the two singles
xor_all = 0
for num in nums:
xor_all ^= num
# Find a bit where the two singles differ
diff_bit = xor_all & (-xor_all) # Lowest set bit
# Partition numbers by this bit and XOR each group
a, b = 0, 0
for num in nums:
if num & diff_bit:
a ^= num
else:
b ^= num
return [a, b]
recognition_signals:
- "find the single/unique element"
- "every element appears twice except one"
- "O(1) extra space"
- "XOR"
- "bit manipulation"
- "without using extra memory"
- "power of 2"
- "count bits"
- "binary representation"
- "toggle"
- "swap without temp"
common_mistakes:
- title: Forgetting XOR order doesn't matter
description: |
XOR is commutative (a⊕b = b⊕a) and associative ((a⊕b)⊕c = a⊕(b⊕c)).
You can process elements in any order and still get the same result.
fix: |
Trust the properties. The order of XOR operations doesn't affect
the final result. Focus on the logic, not the sequence.
- title: Using addition instead of XOR
description: |
Addition doesn't cancel pairs. 2 + 2 = 4, not 0. XOR is special
because a ⊕ a = 0 while a + a = 2a.
fix: |
Remember: XOR cancels identical values, addition accumulates them.
Use ^= for pair cancellation, not +=.
- title: Forgetting to handle negative numbers
description: |
XOR works on the binary representation. Negative numbers use two's
complement, so the bit patterns are different from positive numbers.
fix: |
XOR still works correctly with negative numbers in most languages.
The key properties (a⊕a=0, a⊕0=a) hold for any integer.
- title: Not recognizing the pattern
description: |
Many problems hint at bit manipulation with phrases like "O(1) space"
or "without extra memory" when dealing with duplicates.
fix: |
Look for clues: "appears twice", "unique element", "constant space",
"power of 2". These often signal bit manipulation approaches.
variations:
- name: Single Number (pairs cancel)
description: |
XOR all elements to find the one that appears once when others
appear twice.
example: "Single Number, Single Number II (modular arithmetic)"
- name: Two Single Numbers
description: |
Use XOR to find a differing bit, then partition elements to
separate the two unique numbers.
example: "Single Number III"
- name: Power of Two
description: |
Check if n & (n-1) == 0. Powers of 2 have exactly one set bit.
example: "Power of Two, Power of Four"
- name: Bit Counting
description: |
Count set bits using n &= (n-1) to remove lowest bit each iteration.
example: "Number of 1 Bits, Counting Bits"
- name: Bit Masking
description: |
Use masks to extract, set, clear, or toggle specific bits.
example: "Reverse Bits, Bitwise AND of Numbers Range"
related_patterns:
- greedy
- dynamic-programming
prerequisite_patterns: []