Bit Operations
Master the fundamental bit operations and techniques used in competitive programming and system design.
Basic Bit Operations
AND (&)
- Purpose: Bitwise AND operation
- Result: 1 only if both bits are 1
- Common uses: Masking, checking if bit is set
- Example:
5 & 3 = 1
(101 & 011 = 001)
OR (|)
- Purpose: Bitwise OR operation
- Result: 1 if at least one bit is 1
- Common uses: Setting bits, combining flags
- Example:
5 | 3 = 7
(101 | 011 = 111)
XOR (^)
- Purpose: Bitwise XOR (exclusive OR) operation
- Result: 1 if bits are different
- Common uses: Toggling bits, finding unique elements
- Example:
5 ^ 3 = 6
(101 ^ 011 = 110)
NOT (~)
- Purpose: Bitwise NOT (complement) operation
- Result: Flips all bits
- Common uses: Creating masks, bit inversion
- Example:
~5 = -6
(in 32-bit: ~000...101 = 111...010)
Bit Shifting
Left Shift (<<
)
- Purpose: Shifts bits to the left
- Effect: Multiplies by 2^n
- Example:
5 << 2 = 20
(101 becomes 10100) - Use cases: Fast multiplication, creating masks
Right Shift (>>
)
- Purpose: Shifts bits to the right
- Effect: Divides by 2^n (integer division)
- Example:
20 >> 2 = 5
(10100 becomes 101) - Use cases: Fast division, extracting bits
Arithmetic vs Logical Right Shift
- Arithmetic: Preserves sign bit (signed integers)
- Logical: Fills with zeros (unsigned integers)
Bit Masking
Setting Bits
// Set bit at position i
num |= (1 `<<` i);
Clearing Bits
// Clear bit at position i
num &= ~(1 `<<` i);
Toggling Bits
// Toggle bit at position i
num ^= (1 `<<` i);
Checking Bits
// Check if bit at position i is set
bool isSet = (num & (1 `<<` i)) != 0;
Bit Counting
Count Set Bits (Population Count)
// Method 1: Loop through bits
int count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
// Method 2: Brian Kernighan's algorithm
int count = 0;
while (n) {
n &= (n - 1);
count++;
}
Count Leading/Trailing Zeros
- Leading zeros: Number of zeros before the first 1
- Trailing zeros: Number of zeros after the last 1
- Built-in functions:
__builtin_clz()
,__builtin_ctz()
Common Bit Manipulation Tricks
Power of 2 Check
// Check if n is a power of 2
bool isPowerOfTwo = (n & (n - 1)) == 0;
Get Rightmost Set Bit
// Get the rightmost set bit
int rightmost = n & (-n);
Remove Rightmost Set Bit
// Remove the rightmost set bit
n &= (n - 1);
Swap Without Temporary Variable
// Swap two numbers using XOR
a ^= b;
b ^= a;
a ^= b;
Absolute Value
// Get absolute value without branching
int abs = (n + (n `>>` 31)) ^ (n `>>` 31);
Bit Manipulation in Arrays
Finding Missing Number
- Problem: Array of n-1 numbers from 1 to n, find missing
- Solution: XOR all numbers with 1 to n
Finding Single Number
- Problem: Array where every number appears twice except one
- Solution: XOR all numbers
Finding Two Single Numbers
- Problem: Array where every number appears twice except two
- Solution: XOR to get difference, then separate groups
Bit Manipulation in Strings
Character to Bit Position
// Convert character to bit position
int bitPos = c - 'a'; // for lowercase letters
Check if All Characters Unique
// Using bitmask to check uniqueness
int mask = 0;
for (char c : str) {
int bit = 1 `<<` (c - 'a');
if (mask & bit) return false;
mask |= bit;
}
Performance Tips
- Use bitwise operations for faster arithmetic
- Prefer bitmasks over boolean arrays for small sets
- Use built-in functions when available
- Be careful with signed integers and right shifts
- Consider endianness in multi-byte operations
Common Patterns
- Subset generation: Use bitmasks to represent subsets
- State compression: Use bits to represent states
- Flag combinations: Use OR to combine multiple flags
- Bit manipulation in DP: Use bits to represent visited states