From 4a4a4745dd86ab1554440996121973c39f7d344f Mon Sep 17 00:00:00 2001 From: Kai Chappell Date: Mon, 8 Sep 2025 14:46:22 +0100 Subject: [PATCH] feat(content): bit manipulation pattern --- backend/data/patterns/bit-manipulation.yaml | 229 ++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 backend/data/patterns/bit-manipulation.yaml diff --git a/backend/data/patterns/bit-manipulation.yaml b/backend/data/patterns/bit-manipulation.yaml new file mode 100644 index 0000000..afe8ec0 --- /dev/null +++ b/backend/data/patterns/bit-manipulation.yaml @@ -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: []