Chapter 17

Bit Manipulation & Binary Thinking

Master low-level bit operations to solve complex problems with elegant efficiency. Learn binary arithmetic, bitwise operators, bit tricks, and leverage bitmasks for dynamic programming. Essential for optimizing algorithms and acing technical interviews.

10
Core Topics
6
Bitwise Operators
50+
Code Examples
18
Practice Problems
Table of Contents
17.1

Binary Number System

Numbers in computers are sequences of bits (0s and 1s). Each position represents a power of 2.

Decimal to Binary Conversion

Divide repeatedly by 2 and collect remainders.

C#
// 13 decimal = 1101 binary (8 + 4 + 1)
public static string DecimalToBinary(int n)
{
    if (n == 0) return "0";
    string result = "";
    while (n > 0) {
        result = (n % 2) + result;
        n /= 2;
    }
    return result;
}
// Or: Convert.ToString(13, 2) → "1101"

Bit Widths in C#

TypeBitsRange
byte80 to 255
sbyte8-128 to 127
short16-32k to 32k
int32±2.1B
long64±9.2Q
17.2

Two's Complement & Signed Integers

Negative numbers use two's complement: flip all bits, then add 1.

Two's Complement: ~n + 1 = -n
C#
// 5 in 8-bit: 0000 0101 → Flip: 1111 1010 → Add 1: 1111 1011 = -5
public static int GetNegation(int n) { return (~n) + 1; }

// Right shift difference: signed vs unsigned
int x = -8;  // Arithmetic shift: fills with sign bit
x >> 1;     // -4

uint y = 4294967288; // Same bits as -8 (unsigned)
y >> 1;     // 2147483644 (fills with 0)
17.3

Bitwise Operators

Six core operators: AND (&), OR (|), XOR (^), NOT (~), Left Shift (<<), Right Shift (>>).

AND (&) - Both must be 1

C#
int a = 5;   // 0101
int b = 3;   // 0011
int c = a & b; // 0001 = 1

// Check if i-th bit is set
bool isBitSet = (n & (1 << i)) != 0;

OR (|) - At least one must be 1

C#
int a = 5;   // 0101
int b = 3;   // 0011
int c = a | b; // 0111 = 7

// Set i-th bit to 1
int result = n | (1 << i);

XOR (^) - Bits must differ

C#
int a = 5;   // 0101
int b = 3;   // 0011
int c = a ^ b; // 0110 = 6

// Toggle (flip) i-th bit
int result = n ^ (1 << i);

NOT (~) - Flip all bits

C#
int a = 5;   // 0000...0101
int b = ~a;   // 1111...1010 = -6 (two's complement)

Left Shift (<<) - Multiply by 2^k

C#
int a = 5;      // 0101
int b = a << 1;  // 1010 = 10
int c = a << 2;  // 10100 = 20

Right Shift (>>) - Divide by 2^k

C#
int a = 16;     // 10000
int b = a >> 1;  // 01000 = 8

// For signed: fills with sign bit (arithmetic)
int neg = -8 >> 1; // -4
17.4

Common Bit Tricks

Essential bit manipulation patterns for interviews.

Check if Even/Odd

C#
// Least significant bit (LSB) tells us: 0 = even, 1 = odd
public static bool IsOdd(int n) => (n & 1) == 1;
public static bool IsEven(int n) => (n & 1) == 0;

Check if Power of 2

C#
// Powers of 2: 1 (0001), 2 (0010), 4 (0100), 8 (1000)...
// All have exactly one bit set. Key insight: n & (n-1) removes the rightmost bit.
// If n is power of 2, n & (n-1) == 0
public static bool IsPowerOfTwo(int n) => n > 0 && (n & (n - 1)) == 0;

// Example: 8 (1000) & 7 (0111) = 0000 ✓

Get i-th Bit (0-indexed from right)

C#
public static bool GetBit(int n, int i) 
    => (n & (1 << i)) != 0;

// Example: GetBit(13, 0) = 1 (13 = 1101, rightmost = 1)

Set i-th Bit to 1

C#
public static int SetBit(int n, int i) 
    => n | (1 << i);

// Example: SetBit(8, 0) = 9 (1000 | 0001 = 1001)

Clear i-th Bit (Set to 0)

C#
public static int ClearBit(int n, int i) 
    => n & ~(1 << i);

// Example: ClearBit(13, 0) = 12 (1101 & 1110 = 1100)

Toggle i-th Bit

C#
public static int ToggleBit(int n, int i) 
    => n ^ (1 << i);

// Example: ToggleBit(13, 1) = 15 (1101 ^ 0010 = 1111)

Count Set Bits (1s) - Brian Kernighan's Algorithm

C#
// n & (n-1) removes the rightmost set bit each iteration
public static int CountSetBits(int n)
{
    int count = 0;
    while (n > 0) {
        n &= n - 1;  // Remove rightmost set bit
        count++;
    }
    return count;
}
// Time: O(number of set bits), not O(32)
// Example: CountSetBits(13) → 3 (1101 has three 1s)

Find Rightmost Set Bit

C#
// n & (-n) isolates the rightmost set bit
// Why? -n is two's complement of n
public static int RightmostSetBit(int n) 
    => n & -n;

// Example: RightmostSetBit(13) = 1 (13 = 1101, rightmost bit = 1)
// Example: RightmostSetBit(12) = 4 (12 = 1100, rightmost bit = 0100)
17.5

XOR Properties & Tricks

XOR has special properties that make it ideal for many interview problems.

Key Properties

a ^ a = 0
XORing a value with itself always gives 0. Same bits XORed = different is false.
Use: Eliminate pairs
a ^ 0 = a
XORing with 0 is identity. 0 differs from nothing.
Use: Initialize accumulators
Commutative
a ^ b = b ^ a. Order doesn't matter.
Use: Rearrange operations
Associative
(a ^ b) ^ c = a ^ (b ^ c). Grouping doesn't matter.
Use: Simplify multiple XORs

Swap Two Numbers Without Temp Variable

C#
int a = 5, b = 3;
a = a ^ b;
b = a ^ b;  // b now = original a
a = a ^ b;  // a now = original b
// But: Modern compilers optimize this; temp swap is clearer

Find Single Number (All Others Appear Twice)

C#
// XOR all numbers. Pairs cancel (a^a=0), leaving the single.
public static int FindSingle(int[] nums)
{
    int result = 0;
    foreach (int num in nums)
        result ^= num;
    return result;
}
// Example: [2, 2, 1, 3, 3] → 1 (2^2 cancels, 3^3 cancels)
17.6

Bit Masking & Applications

Use bitmasks to represent sets, track state, or enumerate subsets efficiently.

Creating Masks

C#
// Mask with i-th bit set: (1 << i)
int mask1 = 1 << 3;  // 1000 = bit 3

// Mask with bits [0..i] set: (1 << (i+1)) - 1
int mask2 = (1 << 4) - 1; // 1111 = bits 0-3

// Mask to isolate rightmost i bits: n & ((1 << i) - 1)
int n = 13;  // 1101
int lower2 = n & 3; // 01 = 1 (rightmost 2 bits)

Enumerate All Subsets

C#
// Represent each subset as a bitmask (0 to 2^n - 1)
public static void EnumerateSubsets(int[] arr)
{
    int n = arr.Length;
    for (int mask = 0; mask < (1 << n); mask++)
    {
        // Process subset represented by mask
        List<int> subset = new();
        for (int i = 0; i < n; i++)
            if ((mask & (1 << i)) != 0)
                subset.Add(arr[i]);
        // Use subset...
    }
}
// Time: O(n * 2^n) - explores 2^n subsets

Count Subsets with Property

C#
// Example: Count subsets with even sum
public static int CountEvenSubsets(int[] arr)
{
    int n = arr.Length;
    int count = 0;
    for (int mask = 0; mask < (1 << n); mask++)
    {
        int sum = 0;
        for (int i = 0; i < n; i++)
            if ((mask & (1 << i)) != 0)
                sum += arr[i];
        if (sum % 2 == 0)
            count++;
    }
    return count;
}
// Time: O(n^2 * 2^n) - can optimize with DP
17.7

Bitmask DP

Combine bit masks with dynamic programming for subset and state-based problems.

Subset DP Template

C#
// dp[mask] = some result for subset represented by mask
public static int SubsetDP(int[] arr)
{
    int n = arr.Length;
    int[] dp = new int[1 << n];
    dp[0] = 0;  // Base case: empty set

    // Process each subset
    for (int mask = 1; mask < (1 << n); mask++)
    {
        // Try removing each element to get previous state
        for (int i = 0; i < n; i++)
        {
            if ((mask & (1 << i)) != 0)
            {
                int prevMask = mask ^ (1 << i);
                // dp[mask] = f(dp[prevMask], arr[i])
            }
        }
    }
    return dp[(1 << n) - 1];  // All elements
}
// Space: O(2^n), Time: O(n * 2^n)

Travelling Salesman Problem (TSP) Concept

C#
// dp[mask][i] = min cost to visit cities in mask, ending at city i
public static int TSP(int[][] dist)
{
    int n = dist.Length;
    int[][] dp = new int[1 << n][];
    for (int i = 0; i < (1 << n); i++)
        dp[i] = new int[n];

    // Base: start at city 0
    for (int i = 0; i < n; i++)
        dp[1][i] = int.MaxValue;
    dp[1][0] = 0;

    // Fill DP table
    for (int mask = 1; mask < (1 << n); mask++)
    {
        for (int u = 0; u < n; u++)
        {
            if ((mask & (1 << u)) == 0) continue;
            if (dp[mask][u] == int.MaxValue) continue;
            for (int v = 0; v < n; v++)
            {
                if ((mask & (1 << v)) == 0)
                {
                    int newMask = mask | (1 << v);
                    dp[newMask][v] = Math.Min(dp[newMask][v], 
                        dp[mask][u] + dist[u][v]);
                }
            }
        }
    }

    // Return cost to visit all cities, ending at city 0
    int ans = int.MaxValue;
    for (int i = 0; i < n; i++)
        ans = Math.Min(ans, dp[(1 << n) - 1][i]);
    return ans;
}
// Time: O(n^2 * 2^n), Space: O(n * 2^n)
17.8

LeetCode Problems (1-8)

1
Single Number (LC 136)
Given array where every element appears twice except one. Find the single element. Constraint: O(1) space, O(n) time.
XOREasy

Bit-Level Explanation: XOR cancels pairs (a^a=0), leaving the single element.

C#
public class Solution {
    public int SingleNumber(int[] nums) {
        int result = 0;
        foreach (int num in nums)
            result ^= num;
        return result;
    }
}
// Example: [2, 2, 1] → 1 (2^2=0, 0^1=1)
// Time: O(n), Space: O(1)
2
Single Number II (LC 137)
Every element appears three times except one. Find the single element.
Bit CountMedium

Bit-Level Explanation: Count each bit position across all numbers. Modulo 3 gives the single number's bits.

C#
public int SingleNumberII(int[] nums) {
    int[] bits = new int[32];
    foreach (int num in nums) {
        for (int i = 0; i < 32; i++) {
            if ((num & (1 << i)) != 0)
                bits[i]++;
        }
    }
    int result = 0;
    for (int i = 0; i < 32; i++) {
        if (bits[i] % 3 != 0)
            result |= (1 << i);
    }
    return result;
}
// Time: O(32n), Space: O(32)
3
Single Number III (LC 260)
Array has two unique elements appearing once; rest appear twice. Find both.
XORMedium

Bit-Level Explanation: XOR all elements to get a^b. Find a differing bit. Partition by that bit, XOR each group.

C#
public int[] SingleNumberIII(int[] nums) {
    int xorAll = 0;
    foreach (int num in nums)
        xorAll ^= num;  // xorAll = a ^ b

    // Find rightmost differing bit
    int diffBit = xorAll & -xorAll;

    int a = 0, b = 0;
    foreach (int num in nums) {
        if ((num & diffBit) != 0)
            a ^= num;
        else
            b ^= num;
    }
    return new int[] { a, b };
}
// Time: O(n), Space: O(1)
4
Number of 1 Bits (LC 191)
Count the number of '1' bits in unsigned integer.
Bit CountEasy
C#
// Method 1: Brian Kernighan (optimal for sparse bits)
public int HammingWeight(uint n) {
    int count = 0;
    while (n > 0) {
        n &= n - 1;
        count++;
    }
    return count;
}

// Method 2: Built-in (C# 5.0+)
return System.Numerics.BitOperations.PopCount(n);
5
Counting Bits (LC 338)
For 0 ≤ i ≤ n, count '1' bits in binary of i. Return array.
DP+BitsMedium

Bit-Level Explanation: i & (i-1) removes rightmost bit. dp[i] = dp[i & (i-1)] + 1.

C#
public int[] CountBits(int n) {
    int[] dp = new int[n + 1];
    for (int i = 1; i <= n; i++)
        dp[i] = dp[i & (i - 1)] + 1;
    return dp;
}
// Example: n=2 → [0, 1, 1]
// Time: O(n), Space: O(n)
6
Reverse Bits (LC 190)
Reverse binary representation of 32-bit unsigned integer.
Bit ManipulationEasy
C#
public uint ReverseBits(uint n) {
    uint result = 0;
    for (int i = 0; i < 32; i++) {
        if ((n & (1 << i)) != 0)
            result |= (1u << (31 - i));
    }
    return result;
}
// Example: 43261596 (00000010100101000001111010011100)
// → 964176192 (00111001011110000010100101000000)
// Time: O(32), Space: O(1)
7
Power of Two (LC 231)
Check if integer is power of 2.
Math+BitsEasy

Bit-Level Explanation: Powers of 2 have exactly one bit set. n & (n-1) == 0 identifies them.

C#
public bool IsPowerOfTwo(int n) {
    return n > 0 && (n & (n - 1)) == 0;
}
// Example: IsPowerOfTwo(16) = true (10000 & 01111 = 0)
// Time: O(1), Space: O(1)
8
Missing Number (LC 268)
Array contains n distinct numbers from 0 to n. Find missing number.
XOREasy

Bit-Level Explanation: XOR array with 0..n. Pairs cancel, leaving missing.

C#
public int MissingNumber(int[] nums) {
    int result = 0;
    for (int i = 0; i < nums.Length; i++)
        result ^= i ^ nums[i];
    result ^= nums.Length;
    return result;
}
// Example: [3, 0, 1] → 2
// 0^3 ^ 1^0 ^ 2^1 ^ 3 = 2
// Time: O(n), Space: O(1)
17.9

LeetCode Problems (9-15)

9
Sum of Two Integers (LC 371)
Add two integers without using + or -.
XOR+ANDMedium

Bit-Level Explanation: XOR gives sum without carry. AND << 1 gives carry. Repeat until no carry.

C#
public int GetSum(int a, int b) {
    while (b != 0) {
        int carry = (a & b) << 1;  // Carry bits
        a = a ^ b;                    // Sum without carry
        b = carry;                    // Process carry
    }
    return a;
}
// Example: GetSum(1, 2)
// a=1 (01), b=2 (10)
// Iteration 1: carry=0, a=3, b=0 → return 3
// Note: Works for positive; needs unchecked for negative
10
Bitwise AND of Numbers Range (LC 201)
Given [m, n], find AND of all numbers in range.
Bit PatternMedium

Bit-Level Explanation: Common prefix of m and n remains; all other bits become 0.

C#
public int RangeBitwiseAnd(int m, int n) {
    int shift = 0;
    // Find common prefix by right-shifting both m and n
    while (m != n) {
        m >>= 1;
        n >>= 1;
        shift++;
    }
    // Restore the common prefix
    return m << shift;
}
// Example: RangeBitwiseAnd(5, 7)
// 5=101, 6=110, 7=111 → AND=100=4
// Common prefix after shifting: 1 → shift left by 2 → 100
// Time: O(log(min(m,n))), Space: O(1)
11
Subsets using Bitmask (LC 78)
Generate all subsets of array.
BitmaskMedium
C#
public IList<IList<int>> Subsets(int[] nums) {
    var result = new List<IList<int>>();
    int n = nums.Length;
    
    for (int mask = 0; mask < (1 << n); mask++) {
        var subset = new List<int>();
        for (int i = 0; i < n; i++) {
            if ((mask & (1 << i)) != 0)
                subset.Add(nums[i]);
        }
        result.Add(subset);
    }
    return result;
}
// Example: nums=[1,2,3]
// mask=000 → [], 001 → [1], 010 → [2], 011 → [1,2],
// 100 → [3], 101 → [1,3], 110 → [2,3], 111 → [1,2,3]
// Time: O(n * 2^n), Space: O(n * 2^n)
12
Maximum XOR of Two Numbers (LC 421)
Find max XOR of any two numbers in array.
TrieHard

Bit-Level Explanation: Build trie of bit patterns. For each number, greedily pick opposite bit at each level.

C#
public int FindMaximumXOR(int[] nums) {
    // Build trie of 32-bit numbers
    TrieNode root = new TrieNode();
    foreach (int num in nums) {
        TrieNode node = root;
        for (int i = 31; i >= 0; i--) {
            int bit = (num >> i) & 1;
            if (node.children[bit] == null)
                node.children[bit] = new TrieNode();
            node = node.children[bit];
        }
    }
    
    int maxXor = 0;
    foreach (int num in nums) {
        TrieNode node = root;
        int currentXor = 0;
        for (int i = 31; i >= 0; i--) {
            int bit = (num >> i) & 1;
            int oppBit = 1 - bit;  // Prefer opposite
            if (node.children[oppBit] != null) {
                currentXor |= (1 << i);
                node = node.children[oppBit];
            } else {
                node = node.children[bit];
            }
        }
        maxXor = Math.Max(maxXor, currentXor);
    }
    return maxXor;
}

private class TrieNode {
    public TrieNode[] children = new TrieNode[2];
}
// Time: O(32n), Space: O(32n)
13
UTF-8 Validation (LC 393)
Validate UTF-8 encoded data.
Bit PatternMedium

Bit-Level Explanation: UTF-8: single byte 0xxxxxxx; multi-byte 1xxxxxxx followed by 10xxxxxx bytes.

C#
public bool ValidUtf8(int[] data) {
    int bytesRemaining = 0;
    foreach (int d in data) {
        int byte_ = d & 0xFF;  // Keep only last 8 bits
        
        if (bytesRemaining == 0) {
            if ((byte_ >> 7) == 0) bytesRemaining = 0;  // 0xxxxxxx
            else if ((byte_ >> 5) == 6) bytesRemaining = 1;  // 110xxxxx
            else if ((byte_ >> 4) == 14) bytesRemaining = 2; // 1110xxxx
            else if ((byte_ >> 3) == 30) bytesRemaining = 3; // 11110xxx
            else return false;
        } else {
            if ((byte_ >> 6) != 2) return false;  // Must be 10xxxxxx
            bytesRemaining--;
        }
    }
    return bytesRemaining == 0;
}
// Time: O(n), Space: O(1)
14
Hamming Distance (LC 461)
Find number of positions where bits differ between two integers.
XOREasy
C#
public int HammingDistance(int x, int y) {
    int xor = x ^ y;
    int count = 0;
    while (xor > 0) {
        xor &= xor - 1;  // Remove rightmost set bit
        count++;
    }
    return count;
}
// Example: x=1 (01), y=4 (100)
// XOR = 101 → two 1 bits → Hamming distance = 2
// Time: O(# set bits), Space: O(1)
15
Total Hamming Distance (LC 477)
Find total Hamming distance between all pairs.
Bit CountMedium

Bit-Level Explanation: For each bit position, count 0s and 1s. Contribution = (count0 * count1).

C#
public int TotalHammingDistance(int[] nums) {
    int n = nums.Length;
    int total = 0;
    
    for (int i = 0; i < 32; i++) {
        int ones = 0;
        foreach (int num in nums) {
            if ((num & (1 << i)) != 0)
                ones++;
        }
        int zeros = n - ones;
        total += ones * zeros;  // Pairs with differing bit
    }
    return total;
}
// Example: [1, 3, 5]
// Bit 0: 3 ones, 0 zeros → 0
// Bit 1: 1 one, 2 zeros → 2
// Bit 2: 2 ones, 1 zero → 2
// Total = 4
// Time: O(32n), Space: O(1)
17.10

Operator Precedence & Interview Tips

Bitwise Operator Precedence (High to Low)

PrecedenceOperatorNote
1 (Highest)~ (NOT)Unary, evaluated right-to-left
2<< and >>Shifts bind tighter than comparisons
3& (AND)Tighter than ^ and |
4^ (XOR)
5| (OR)Loosest of bitwise ops
6==, !=Comparison operators

Common Pitfalls

Precedence Issues: Always use parentheses with shift operators. n & 1 << 2 = n & (1 << 2), not (n & 1) << 2
C#
// WRONG: Check if bit 2 is set
if (n & 1 << 2) { }  // Evaluated as n & (1 << 2) ✓ but accidentally correct

// WRONG: Comparison with bitwise
if (n & 1 == 1) { }  // = n & (1 == 1) = n & 1 (wrong semantics)

// RIGHT
if ((n & 1) == 1) { }

Handling Negative Numbers

C#
// Right shift behavior differs for signed vs unsigned
int x = -8;       // Arithmetic shift (fills with sign bit)
x >> 1;         // -4

uint y = (uint)-8;  // Cast to unsigned
y >> 1;         // Large positive (logical shift)

// For absolute right shift (logical): use unsigned or cast
uint logical = ((uint)x) >> 1;

Interview Tips

Tip 1
Always Use Parentheses
Make precedence explicit. (n & (1 << i)) is clearer than n & 1 << i.
Tip 2
Recognize XOR Patterns
When you need to find unpaired elements or swap, think XOR immediately.
Tip 3
Bit Tricks for Efficiency
n & (n-1) is powerful for counting/removing bits. Know it cold.
Tip 4
Avoid Overflow
Left shift can overflow. Use unchecked in C# if intentional, or use long.
Tip 5
Think Bit-by-Bit
When stuck, process bits individually or draw out binary representations.
Tip 6
Test Edge Cases
Test with 0, -1, 1, powers of 2, and max/min integers. Bit ops have surprises.

Problem-Solving Strategy

1
Identify the pattern: Are you finding unpaired elements (XOR), counting bits (loop + mask), or representing subsets (bitmask)?
2
Draw binary: Write out bit patterns for examples. Patterns become obvious.
3
Use bit tricks: Apply n & (n-1), n & -n, XOR properties, etc.
4
Verify: Test on examples, especially edge cases (0, negatives, powers of 2).
5
Optimize: Reduce bit widths used, minimize iterations, combine operations.

Useful C# BitOperations (.NET 5.0+)

C#
using System.Numerics;

// Count set bits (population count)
int setBits = BitOperations.PopCount(13);  // 3

// Leading zero count
int leadingZeros = BitOperations.LeadingZeroCount(8);  // 28 (in 32-bit)

// Trailing zero count
int trailingZeros = BitOperations.TrailingZeroCount(8);  // 3

// Rotate bits
int rotated = BitOperations.RotateLeft(5, 2);   // Left rotate
17.B

Advanced Bit Tricks & Optimizations

Rare but powerful techniques for highly optimized bit manipulation.

Gray Code

Binary encoding where successive values differ by one bit. Useful in error detection and digital electronics.

C#
// Convert binary to Gray code
public static int BinaryToGray(int n) 
    => n ^ (n >> 1);

// Convert Gray code back to binary
public static int GrayToBinary(int gray) {
    int binary = gray;
    while (gray > 0) {
        gray >>= 1;
        binary ^= gray;
    }
    return binary;
}

// Example: 5 (binary 0101) → 0111 (Gray)
// Gray 0111 → 0101 (back to 5)

Popcount Variants & Fast Bit Operations

C#
// Parity: is popcount odd or even?
public static bool HasOddParity(int n) {
    n ^= n >> 16;
    n ^= n >> 8;
    n ^= n >> 4;
    n ^= n >> 2;
    n ^= n >> 1;
    return (n & 1) == 1;
}

// Nearest power of 2 greater than n
public static int NextPowerOfTwo(int n) {
    n--;
    n |= n >> 1;
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    n |= n >> 16;
    return n + 1;
}

// Example: NextPowerOfTwo(5) = 8, NextPowerOfTwo(8) = 16

Bit Interleaving (Morton Code / Z-Order Curve)

Interleave bits of two numbers for spatial indexing.

C#
// Interleave bits of x and y
public static ulong Interleave(uint x, uint y) {
    ulong result = 0;
    for (int i = 0; i < 32; i++) {
        result |= (((ulong)x & (1u << i)) << i) |
                  (((ulong)y & (1u << i)) << (i + 1));
    }
    return result;
}

// Example: x=3 (11), y=2 (10) → 1101 (interleaved)
// Bit positions: y[1] x[1] y[0] x[0] = 1 1 1 1

Find Isolation of Rightmost Difference

C#
// Find rightmost bit position where two numbers differ
public static int RightmostDifferenceBit(int a, int b) {
    int xor = a ^ b;
    return xor & -xor;  // Isolate rightmost set bit
}

// Example: a=5 (0101), b=3 (0011) → XOR=0110 → rightmost=0010

Check if Number is Subset of Bits

C#
// Check if all set bits of 'a' are also set in 'b'
public static bool IsBitSubset(int a, int b) {
    return (a & b) == a;
}

// Example: a=5 (0101), b=7 (0111) → (0101 & 0111) = 0101 = 5 ✓
// Example: a=6 (0110), b=5 (0101) → (0110 & 0101) = 0100 ≠ 6 ✗
17.E

Extended Practice & Applications

Bit Manipulation in Real-World Contexts

Where bit manipulation actually matters in production code:

Network Masks
IP subnetting uses bitmasks to identify network and host portions. A /24 network mask is 255.255.255.0 in dotted decimal, or binary with rightmost 24 bits for host.
Permissions Flags
Unix file permissions (rwxrwxrwx) are stored as 9 bits. Checking read permission = check bit 8, write = bit 7, execute = bit 6.
Graphics Pixels
RGBA color: 32-bit value. Red = bits 24-31, Green = 16-23, Blue = 8-15, Alpha = 0-7. Extract with shifts and masks.
Compression
Huffman coding, bit packing, and run-length encoding all manipulate bit-level data for space efficiency.

Common Bit Manipulation Patterns Summary

PatternCodeUse Case
Check bit i(n >> i) & 1Test single bit
Set bit in | (1 << i)Enable flag
Clear bit in & ~(1 << i)Disable flag
Toggle bit in ^ (1 << i)Switch state
Check if power of 2(n & (n-1)) == 0Validate magnitude
Rightmost set bitn & -nIsolate LSB
Remove rightmost setn & (n-1)Decrement bits
Count set bitswhile(n) n&=n-1; count++Population count
Isolate differencea ^ bFind changes
Merge optionsa | bCombine flags

Complexity Analysis for Bit Operations

Understanding the computational cost of bitwise operations:

Single Bit Op
Checking, setting, or toggling a single bit with mask: O(1). Hardware direct.
Loop Over Bits
Brian Kernighan loop (remove bits): O(k) where k = popcount, not O(32).
Subset Enumeration
Generate all subsets of n items: O(n × 2ⁿ). Feasible for n ≤ 20.
Bitmask DP
TSP, Hamiltonian path: O(n² × 2ⁿ). Slower but optimal for small n.

Debugging Bit-Level Code

💡Pro Tip: When debugging bit operations, print numbers in binary: Convert.ToString(n, 2) shows you exactly what's happening at each step.
C#
// Debug helper: visualize bit operations
public static void DebugBits(int n, string label = "") {
    string binary = Convert.ToString(n, 2).PadLeft(32, '0');
    Console.WriteLine($"{label,-20} {n,12} {binary}");
}

// Usage:
int x = 5;
DebugBits(x, "Original");
DebugBits(x << 1, "After << 1");
DebugBits(x & 3, "After & 3");

// Output shows binary clearly for verification
17.A1

Advanced Submask & SOS DP

Fast algorithms for subset enumeration and sum over subsets.

Submask Iteration Pattern

Iterate all submasks of a bitmask in O(3^n) total time across all masks.

C#
for (int submask = mask; submask > 0; submask = (submask - 1) & mask) {
    // Each submask is processed exactly once
}
// Key: (submask - 1) & mask gives next smaller submask
// Example mask = 1101 (13): submasks are 1101, 1100, 1001, 1000, 0101, 0100, 0001

Sum Over Subsets (SOS DP)

Compute sum of values for all submasks of each mask in O(n * 2^n) time.

C#
public static int[] SumOverSubsets(int[] arr, int maxBits) {
    int n = 1 << maxBits;
    int[] dp = new int[n];
    Array.Copy(arr, dp, Math.Min(arr.Length, n));
    
    for (int i = 0; i < maxBits; i++) {
        for (int mask = 0; mask < n; mask++) {
            if ((mask & (1 << i)) != 0)
                dp[mask] += dp[mask ^ (1 << i)];
        }
    }
    return dp;
}
// Time: O(maxBits * 2^maxBits), Space: O(2^maxBits)
17.A2

Bit Tricks for Performance

Micro-optimizations using bit manipulation in critical code paths.

Fast Modulo for Powers of 2

C#
// Modulo by power of 2 is much faster as AND operation
int slow = n % 16;    // Division: 5-20 cycles
int fast = n & 15;    // AND: 1 cycle (15 = 16 - 1 = 0xF)

// General rule: n % 2^k = n & (2^k - 1)
// The low k bits of n equal n mod 2^k

Branchless Sign Function

C#
// Returns 1 if x > 0, -1 if x < 0, 0 if x == 0
public static int Sign(int x) {
    return (x >> 31) | (-x >> 31);
}

// Why? If x > 0: first shift = 0, second shift = 0, OR = 0
// If x < 0: first shift = -1, second shift = 0, OR = -1
// Hmm, this returns -1 not 1. Better version:

public static int SignCorrect(int x) {
    return ((x >> 31) & -2) + (x > 0 ? 1 : 0);
}

Branchless Absolute Value

C#
public static int AbsBranchless(int x) {
    int signMask = x >> 31;  // -1 if negative, 0 if positive
    return (x + signMask) ^ signMask;
}

// Logic: if negative, add -1 then XOR with -1 (flip all bits)
// This applies two's complement: -x = ~x + 1
17.A3

Common Pitfalls & Debugging

Mistakes that catch experienced programmers when working with bits.

Left Shift Overflow

Danger: 1 << 31 overflows in signed 32-bit. Use long or limit shifts to 30.
C#
// WRONG
int mask = (1 << 31) - 1;  // Overflow before subtraction

// CORRECT
long mask = (1L << 31) - 1;  // 0x7FFFFFFF
int mask2 = -1;               // All bits set (0xFFFFFFFF)

Signed vs Unsigned Right Shift

Watch: Signed right shift fills with sign bit; unsigned fills with 0. This varies by language.
C#
// Signed: arithmetic shift (extends sign bit)
int x = -8;
x >> 2;  // -2 (fills with 1s)

// Unsigned: logical shift (fills with 0s)
uint y = 4294967288;  // Same bits as -8
y >> 2;  // 1073741822 (fills with 0s)

Operator Precedence Traps

Always use parentheses! Shift and comparison operators have tricky precedence.
C#
// CONFUSING: Check if bit i is set
if (n & 1 << i) { }  // Works but misleading

// CLEAR: Explicitly show what you mean
if ((n & (1 << i)) != 0) { }

// WRONG: Comparison operator has lower precedence than AND
if (n & 1 == 1) { }  // Evaluates as n & (1 == 1) = n & 1

// RIGHT
if ((n & 1) == 1) { }

XOR Swap Pitfall

Avoid: XOR swap fails when a and b are the same variable.
C#
// XOR SWAP with same variable: BROKEN
int a = 5;
a ^= a;  // a becomes 0
a ^= a;  // a remains 0
a ^= a;  // a remains 0  -- NOT 5!

// Use temp swap: clearer and faster on modern CPUs
int temp = a;
a = b;

    
17.R

Quick Reference & Cheat Sheet

A compact summary of all bit manipulation techniques for quick lookup during interviews.

One-Line Bit Operations

OperationCodeReturns
Get bit i(n >> i) & 10 or 1
Set bit in | (1 << i)n with bit i=1
Clear bit in & ~(1 << i)n with bit i=0
Toggle bit in ^ (1 << i)n with bit i flipped
Check if even(n & 1) == 0true/false
Check if power of 2(n & (n-1)) == 0 && n > 0true/false
Rightmost set bitn & -nisolates LSB
Remove rightmost setn & (n-1)clears LSB
Count set bitsSystem.Numerics.BitOperations.PopCount(n)count of 1s
Isolate lower k bitsn & ((1 << k) - 1)bottom k bits

Bitmask DP Template

C#
// Enumerate all subsets: O(2^n)
for (int mask = 0; mask < (1 << n); mask++) {
    // Process subset represented by mask
}

// Enumerate all submasks: O(3^n total)
for (int submask = mask; submask > 0; submask = (submask - 1) & mask) {
    // Process submask
}

// DP over subsets: O(n * 2^n) or O(n^2 * 2^n)
int[] dp = new int[1 << n];
dp[0] = 0;  // Base case: empty set
for (int mask = 1; mask < (1 << n); mask++) {
    // Try removing each element
    for (int i = 0; i < n; i++) {
        if ((mask & (1 << i)) != 0) {
            int prev = mask ^ (1 << i);
            // dp[mask] = f(dp[prev], element[i])
        }
    }
}

XOR Properties Quick Lookup

a ^ a = 0
Any value XORed with itself is 0.
a ^ 0 = a
XORing with 0 is identity operation.
a ^ b = b ^ a
XOR is commutative.
(a ^ b) ^ c = a ^ (b ^ c)
XOR is associative.
a ^ a ^ b = b
Pairs cancel; use for finding unpaired elements.
a ^ (~a) = all 1s
XORing a value with its inverse gives full mask.

Interview Question Classification

By XOR: Single Number (136), Single Number II (137), Single Number III (260), Missing Number (268)

By Counting Bits: Number of 1 Bits (191), Counting Bits (338), Hamming Distance (461), Total Hamming Distance (477)

By Bit Tricks: Power of Two (231), Reverse Bits (190), Sum of Two Integers (371)

By Bitmask: Subsets (78), Maximum XOR (421), UTF-8 Validation (393), Bitwise AND of Range (201)

By DP: Travelling Salesman, Maximum Weight Independent Set, Assign Cookies to Groups

Complexity Reference

ApproachTimeSpaceWhen to Use
Single Pass (XOR)O(n)O(1)Unpaired elements, simple XOR tricks
Bit Counting LoopO(k * n) where k=popcountO(32) or O(64)Counting bits in array
Subset EnumerationO(n * 2^n)O(1)Small n ≤ 20, checking all subsets
Submask DPO(3^n)O(2^n)Dependency between subsets, n ≤ 20
Bitmask DPO(n^2 * 2^n)O(n * 2^n)TSP, Hamiltonian paths, n ≤ 16

Last-Minute Tips for Interviews

1
Draw Binary Representations
Write out bit patterns for small examples. Patterns become obvious visually.
2
Test Edge Cases First
Test with 0, -1, 1, powers of 2, max/min values. Bit ops surprise often.
3
Use Parentheses Always
Even if operator precedence seems clear, add parentheses. Clarity > cleverness.
4
Know Your Primitives
Understand bit widths (int=32, long=64) and signed vs unsigned behavior in your language.
5
Recognize XOR Patterns Instantly
Problems with unpaired elements, swapping, or toggling often scream for XOR.
6
n & (n-1) is Your Best Friend
Removes rightmost set bit. Essential for counting, powers of 2, and many tricks.
Conclusion

Mastering Bit Manipulation

Bit manipulation bridges the gap between high-level algorithms and low-level hardware efficiency. It's a skillset that compounds: early mastery pays dividends across interviews, competitive programming, and optimization-critical code.

Your Learning Path Forward

1
Memorize Basics: Operator truth tables, two's complement, bit widths in your language. Spend one day here.
2
Learn Tricks: Power of 2 check, count bits, set/clear/toggle bits. Practice on LeetCode Easy tier (191, 231, 461).
3
Master XOR: Work through all XOR-based problems (136, 137, 260, 268). XOR is the gateway to intermediate problems.
4
Solve Medium Problems: Tackle mask-based problems and DP (78, 421, 338, 477). Understand bitmask DP template thoroughly.
5
Challenge Yourself: Solve hard problems and competitive programming problems. Implement TSP, SOS DP, and advanced techniques.
6
Optimize & Teach: Optimize your solutions for speed/space. Explain bit tricks to others to deepen understanding.

Resources for Continued Learning

Practice Platforms: LeetCode (sorted by topic), Codeforces (bit manipulation tag), AtCoder, HackerRank. Do 30-50 problems across difficulties.
💡Advanced Topics: After mastering this chapter, explore Gray code, Hamming codes, cryptography basics, and GPU/SIMD bit-level parallelism.

Final Checklist Before an Interview

Can you answer "yes" to all?

Know Your Foundations
Explain two's complement from scratch
Draw why n & (n-1) removes the rightmost bit
List all 6 bitwise operators and their uses
Explain signed vs unsigned right shift
Solve Common Problems
Single Number variants (15 min each)
Bit counting and XOR swaps (10 min each)
Power of 2 and bit tricks (5 min each)
Bitmask subset enumeration (20 min)

Now go solve bit problems and ace that interview.

b = temp;