Chapter 10: Bit Manipulation
Master bitwise operations, common tricks, and XOR patterns. Learn when and where to use bit manipulation.
1. Bitwise Operations
📌 When and Where to Use
- Efficient operations: Faster than arithmetic operations
- Set operations: Representing sets as bits
- Flags: Storing multiple boolean flags in one integer
- Real-world example: Permission systems, feature flags, set operations, or optimization problems
Common Bitwise Operations
# AND: & (both bits must be 1)
5 & 3 # 101 & 011 = 001 = 1
# OR: | (at least one bit is 1)
5 | 3 # 101 | 011 = 111 = 7
# XOR: ^ (bits differ)
5 ^ 3 # 101 ^ 011 = 110 = 6
# NOT: ~ (flip all bits)
~5 # ~101 = ...11111010 (depends on bit width)
# Left Shift: << (multiply by 2^n)
5 << 2 # 101 << 2 = 10100 = 20 (5 * 4)
# Right Shift: >> (divide by 2^n)
20 >> 2 # 10100 >> 2 = 101 = 5 (20 / 4)
2. Single Number (XOR Pattern)
Example: Find Single Number
Problem: Every number appears twice except one. Find the single number.
def single_number(nums):
"""
Find single number using XOR.
Args:
nums: List where every number appears twice except one
Returns:
The single number
"""
# Step 1: Initialize result
result = 0
# Step 2: XOR all numbers
for num in nums:
# Step 2a: XOR operation
# XOR properties:
# - a ^ a = 0 (same number cancels out)
# - a ^ 0 = a (XOR with 0 returns number)
# - XOR is commutative and associative
result ^= num
# Step 3: Return result
# All pairs cancel out (a ^ a = 0)
# Only single number remains
return result
Step-by-Step Code Walkthrough:
Step 1 - Initialize: Start with result = 0.
Step 2 - XOR All: For each number:
- Step 2a: XOR with result
- Pairs cancel out (a ^ a = 0)
- Single number remains
Step 3 - Return: Result contains the single number.
Why it works: XOR is commutative and associative. All pairs cancel to 0, leaving only the single number.
Example:
nums = [4, 1, 2, 1, 2]
4 ^ 1 ^ 2 ^ 1 ^ 2 = 4 ^ (1 ^ 1) ^ (2 ^ 2) = 4 ^ 0 ^ 0 = 4
3. Count Set Bits
Example: Number of 1 Bits
def count_bits(n):
"""
Count number of set bits (1s) in binary representation.
Args:
n: Integer
Returns:
Number of set bits
"""
count = 0
# Step 1: Continue while n > 0
while n:
# Step 2: Check if least significant bit is 1
# n & 1 checks if last bit is set
if n & 1:
count += 1
# Step 3: Right shift to check next bit
# n >>= 1 moves to next bit
n >>= 1
return count
Step-by-Step Code Walkthrough:
Step 1 - Loop: Continue while n > 0.
Step 2 - Check Bit: n & 1 checks if least significant bit is 1. If yes, increment count.
Step 3 - Shift: n >>= 1 right shifts to check next bit.
Optimized Version (Brian Kernighan's Algorithm)
def count_bits_optimized(n):
"""
Count set bits using Brian Kernighan's algorithm.
Key insight: n & (n - 1) clears the rightmost set bit.
"""
count = 0
# Step 1: Continue while n > 0
while n:
# Step 2: Clear rightmost set bit
# n & (n - 1) removes the rightmost 1
n = n & (n - 1)
count += 1
return count
Step-by-Step Code Walkthrough:
Step 1 - Loop: Continue while n > 0.
Step 2 - Clear Bit: n & (n - 1) clears the rightmost set bit. Each iteration removes one set bit.
Time Complexity: O(k) where k is number of set bits (better than O(log n)).
4. Power of Two
Example: Check if Number is Power of 2
def is_power_of_two(n):
"""
Check if n is a power of 2.
Args:
n: Positive integer
Returns:
True if n is power of 2, False otherwise
"""
# Step 1: Handle edge case
if n <= 0:
return False
# Step 2: Power of 2 has exactly one set bit
# n & (n - 1) clears the rightmost set bit
# If result is 0, n had exactly one set bit
return (n & (n - 1)) == 0
Step-by-Step Code Walkthrough:
Step 1 - Edge Case: Powers of 2 are positive, so n must be > 0.
Step 2 - Check: Powers of 2 have exactly one set bit. n & (n - 1) clears it. If result is 0, n is power of 2.
Example: 8 = 1000, 8 & 7 = 1000 & 0111 = 0 → True
5. Missing Number
Example: Find Missing Number Using XOR
Problem: Array contains n distinct numbers in range [0, n]. One is missing. Find it.
def missing_number(nums):
"""
Find missing number using XOR.
Args:
nums: Array of n distinct numbers in range [0, n] (one missing)
Returns:
Missing number
"""
# Step 1: XOR all numbers in array
result = 0
for num in nums:
result ^= num
# Step 2: XOR with all numbers from 0 to n
# This includes the missing number
for i in range(len(nums) + 1):
result ^= i
# Step 3: Result is the missing number
# All numbers appear twice (once in nums, once in range)
# Except missing number (appears only in range)
return result
Step-by-Step Code Walkthrough:
Step 1 - XOR Array: XOR all numbers in the array.
Step 2 - XOR Range: XOR with all numbers from 0 to n (complete range).
Step 3 - Result: All numbers appear twice (cancel out) except the missing number.
Example:
nums = [3, 0, 1], n = 3
XOR array: 3 ^ 0 ^ 1 = 2
XOR range: 2 ^ 0 ^ 1 ^ 2 ^ 3 = 2
Missing: 2
6. Reverse Bits
Example: Reverse Bits of 32-bit Integer
def reverse_bits(n):
"""
Reverse bits of 32-bit unsigned integer.
Args:
n: 32-bit unsigned integer
Returns:
Integer with reversed bits
"""
result = 0
# Step 1: Process all 32 bits
for i in range(32):
# Step 2: Extract bit at position i
# (n >> i) & 1 gets the i-th bit
bit = (n >> i) & 1
# Step 3: Place bit at reversed position
# Position i should go to position (31 - i)
# Left shift to correct position and OR with result
result |= (bit << (31 - i))
# Step 4: Return reversed bits
return result
Step-by-Step Code Walkthrough:
Step 1 - Loop: Process all 32 bits.
Step 2 - Extract Bit: (n >> i) & 1 gets the i-th bit from right.
Step 3 - Place Bit: Place bit at position (31 - i) using left shift and OR.
Step 4 - Return: Result contains reversed bits.
📚 Chapter Summary
- XOR Properties: a ^ a = 0, a ^ 0 = a, commutative and associative
- Common Tricks: n & (n - 1) clears rightmost set bit, n & 1 checks if odd
- Set Bits: Count using loop or Brian Kernighan's algorithm
- Power of 2: Check if (n & (n - 1)) == 0
- Bit Manipulation: Often more efficient than arithmetic operations
Key Takeaway: Bit manipulation is powerful for optimization and set operations. XOR is particularly useful for finding unique elements. Remember common patterns like clearing rightmost bit.