DSA Field Notes
Course map / 12 Bit Manipulation
NeetCode · DSA for Beginners · Lesson 34

Bit Manipulation Field Notes

Bits, the five operators, shifting, and the tricks built on them: count the 1s, clear the lowest bit, cancel pairs with XOR, use an integer as a set. Every diagram shows the bits as boxes so you can see what moved.

0Why bits are worth one lesson

Analogy

A row of eight light switches on a wall. Each switch is either up (1) or down (0). Nothing else. Every number, letter, and pixel in a computer is just a long row of these switches. Bit manipulation is the skill of reading and flipping the switches directly, instead of asking the computer to do arithmetic for you.

NeetCode puts this lesson last on purpose. It is not an algorithm and not a data structure. It is a CS concept: a set of tricks that make some algorithms simpler or faster. These questions are less common in interviews than arrays or trees, but they show up, and they are hard to solve if you do not know the trick. You either know it or you do not. So learn the five operators and the four patterns below, and you are covered.

Recall from the first chapter: a bit (binary digit) is the most fundamental unit a computer uses to represent data. It holds 0 or 1. Eight bits make a byte. An int in most languages is 32 or 64 bits.

128 64 32 16 8 4 2 1 value 0 0 0 1 0 1 1 1 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 00010111 = 16 + 4 + 2 + 1 = 23 add the place values of the boxes that hold a 1; ignore the zeros
A number is a row of boxes, each worth a power of 2. The rightmost box is bit 0 and is worth 1. Each box to the left is worth twice as much. 23 has 1s in the 16, 4, 2 and 1 boxes. This picture is the whole topic: every trick below is "look at one box" or "slide the boxes".

1Reading and writing binary

Binary to decimal and back

In decimal (base 10) each position is a power of 10: ones, tens, hundreds. In binary (base 2) each position is a power of 2. Counting from the right: 1, 2, 4, 8, 16, 32, ... So 001 is 1, 010 is 2, 100 is 4, and 10111 is 16 + 4 + 2 + 1 = 23. This one rule converts any binary number to decimal.

Going the other way, keep dividing by 2 and write down the remainders from last to first. 23 → 11 r1 → 5 r1 → 2 r1 → 1 r0 → 0 r1. Reading the remainders backwards: 10111. You will see this exact division in the countBits loop below, because n >> 1 is n // 2.

BinaryPlace values that are onDecimal
00111
01022
10044
01114 + 2 + 17
100088
1011016 + 4 + 222
1011116 + 4 + 2 + 123
11111111128 + 64 + 32 + 16 + 8 + 4 + 2 + 1255

Python does the conversion for you

Three tools. bin() turns an int into a string that starts with 0b. int(s, 2) parses a binary string. format (or an f-string) gives you a padded string for printing traces. You can also type a binary literal directly with the 0b prefix.

bin(23)              # '0b10111'   (a string, prefix 0b)
bin(23)[2:]          # '10111'     (drop the prefix)
format(23, "08b")     # '00010111'  (pad to 8 places: the byte in the picture)
f"{23:b}"            # '10111'

int("10111", 2)      # 23          (string in base 2 → int)
int("00010111", 2)   # 23          (leading zeros are fine)
0b10111              # 23          (binary literal, no quotes)
Keep in mind

bin(n) is for looking at a number. The number itself is always stored as bits; there is no "decimal int" and "binary int" in Python. 23 and 0b10111 are the same object.

2The five operators and their truth tables

A truth table lists every input combination and the output. For two bits there are only four combinations, so each table has four rows. The operators work on whole numbers by applying the table to each bit position separately: bit 0 with bit 0, bit 1 with bit 1, and so on.

  • AND &: both bits must be 1 to get 1; otherwise 0.
  • OR |: only one bit has to be 1 to get 1. Also 1 if both are 1. 0 only if both are 0.
  • XOR ^ (exclusive or): 1 if only ONE of the bits is 1; otherwise 0. So 1 ^ 1 = 0. Think "are they different?".
  • NOT ~ (negation): flips the bit. ~0 = 1, ~1 = 0. It takes one input, not two.
  • Shift << left, >> right: slides every bit one position. Left shift multiplies by 2 (doubling). Right shift divides by 2 (halving).
AND a & b aba&b 000 010 100 111 OR a | b aba|b 000 011 101 111 XOR a ^ b aba^b 000 011 101 110 NOT ~a a~a 01 10 one input just flips it teal 1 = the rows to memorize. AND: only 1,1. OR: anything but 0,0. XOR: only when different.
Four tables, twelve rows total. AND is strict (both), OR is generous (either), XOR is "different?". Notice XOR's last row: 1 ^ 1 = 0. That single row is why XOR can cancel pairs, which is the trick in section 5.

The same operators in Python

This is the lesson's code, line for line. Every line here was run.

# AND
n = 1 & 1       # 1

# OR
n = 1 | 0       # 1

# XOR
n = 0 ^ 1       # 1

# NOT (negation)
n = ~n          # -2  (why not 0? see section 4: ~n is -n - 1 in Python)

# Bit shifting
n = 1
n = n << 1      # 2   (001 → 010, doubled)
n = n >> 1      # 1   (010 → 001, halved)

Left shift: slide left, a 0 comes in, the top bit can fall off

Start with 001 (decimal 1) in a 3-bit register and shift left three times. In the last step the 1 is truncated: it falls off the end and is replaced by 0. There is no room to keep it.

001 << 1 = 010   # 1 → 2
010 << 1 = 100   # 2 → 4
100 << 1 = 000   # 4 → 0   the 1 fell off the left edge
4 2 1 start 0 0 1 = 1 ① 001 << 1 0 1 0 = 2 ② 010 << 1 1 0 0 = 4 ③ 100 << 1 0 0 0 = 0 1 truncated: no box to land in each step a 0 enters on the right
Orange = the bit that moved this step. Steps ① and ② double the number: 1, 2, 4. Step ③ pushes the 1 past the left edge of the 3-bit register, so the result is 0, not 8. In a language with fixed-width ints this is overflow. Python does not do this (section 4), but hardware and most other languages do.

Right shift: slide right, the lowest bit falls off, the value halves

Right shift is the mirror. Every bit moves one box to the right, so every place value halves: the 16 becomes an 8, the 4 becomes a 2. The bit in the 1s box has nowhere to go and is dropped. That dropped bit is exactly the remainder of dividing by 2, which is why n >> 1 equals n // 2.

16 8 4 2 1 22 = 1 0 1 1 0 16 + 4 + 2 lowest bit drops (the remainder of ÷ 2) 22 >> 1 = 0 1 0 1 1 8 + 2 + 1 = 11 every place value halves: 16 → 8, 4 → 2, 2 → 1. 23 >> 1 is also 11: its dropped bit is a 1, the remainder of 23 // 2.
Shift right once = divide by 2 and throw away the remainder. 22 becomes 11. A 0 enters on the left. Shifting by k divides by 2**k; n >> 3 is n // 8. Likewise n << k is n * 2**k.
Shifts bind loosely

In Python, + and - are evaluated before << and >>. So 1 << k + 1 means 1 << (k + 1), not (1 << k) + 1. Put parentheses around every shift that sits next to arithmetic.

3Demonstration: count the 1 bits in 23

The lesson's worked example. 23 in binary is 10111. The plan: look at the lowest bit, then shift right so the next bit becomes the lowest, and repeat until all bits are 0.

How do we look at the lowest bit? With AND. Because 1 & 1 = 1 and 0 & 1 = 0, the expression n & 1 keeps only bit 0 and zeroes everything else. If n & 1 == 1, the lowest bit is on and we increment count. Then n = n >> 1 throws that bit away.

# Counting Bits
def countBits(n):
    count = 0
    while n > 0:
        if n & 1 == 1:      # is the lowest bit a 1?
            count += 1
        n = n >> 1          # same as n // 2: drop the lowest bit
    return count

countBits(23)   # 4
turn 16 8 4 2 1 n & 1 count n >> 1 ① 1 0 1 1 1 1 1 01011 ② 0 1 0 1 1 1 2 00101 ③ 0 0 1 0 1 1 3 00010 ④ 0 0 0 1 0 0 3 (no change) 00001 ⑤ 0 0 0 0 1 1 4 00000 → stop orange box = the bit that n & 1 reads this turn. n >> 1 then throws it away and the next bit slides into that box.
Five turns, four 1s. Each turn reads bit 0 and then shifts. Turn ④ reads a 0, so count stays at 3. After turn ⑤ the number is 0 and while n > 0 stops. The loop runs once per bit in the number, about log2(n) times, not n times.
Turnnn & 00001Lowest bitcountn >> 1 →
110111 (23)000011101011 (11)
201011 (11)000011200101 (5)
300101 (5)000011300010 (2)
400010 (2)0000003 (just shift)00001 (1)
500001 (1)000011400000 (0), loop ends

Count = 4. Check it against the byte picture in section 0: 23 has 1s in the 16, 4, 2 and 1 boxes. Four boxes.

The one-liners Python gives you

In real code use the built-ins. In an interview, write the loop first, then mention these.

bin(23).count("1")   # 4   works on every Python version
(23).bit_count()      # 4   Python 3.10+, fastest; note the parentheses around the literal
(23).bit_length()     # 5   how many bits it takes to write 23 (10111)
Keep in mind

The number of 1 bits has a name: the popcount or Hamming weight. LeetCode 191 asks for exactly this. Section 5 shows a second way to count that skips the 0 bits entirely.

4Python ints, negatives, and masks

Python ints do not overflow

In C, Java, or on the CPU, an int has a fixed width (32 or 64 bits). Shift a 1 past the top and it is gone, as in the 3-bit register above. Python ints are arbitrary precision: they grow as many bits as the value needs. 1 << 100 is simply 2100, a 31-digit number. Nothing falls off on the left. The only bits Python ever drops are the ones you push off the right with >>.

1 << 3        # 8, not 0: Python has no 3-bit register
1 << 100      # 1267650600228229401496703205376
(1 << 100) > 0  # True, no wrap-around to negative

# when a problem says "32-bit", cut to 32 bits yourself:
MASK = 0xFFFFFFFF        # 32 ones
(1 << 35) & MASK          # 0: bits above 31 removed

Why ~n is -n - 1

Hardware stores negative numbers in two's complement: to get -x in a fixed width, flip every bit of x and add 1. The top bit then acts as the sign. In 8 bits, 5 is 00000101, flipping gives 11111010, adding 1 gives 11111011, which is -5. Python behaves as if the number had infinitely many sign bits on the left, so ~n (flip every bit) is always -n - 1: ~0 == -1, ~1 == -2, ~23 == -24. That is why the lesson's n = ~n on 1 gives -2, not 0.

~0              # -1
~1              # -2
~23             # -24
bin(-5)         # '-0b101'  Python prints sign + magnitude, not the bit pattern
(-5) & 0xFF     # 251 = 0b11111011  the 8-bit two's complement pattern
-8 >> 1         # -4  right shift keeps the sign (arithmetic shift)
-7 >> 1         # -4  rounds toward minus infinity, exactly like -7 // 2
Negative numbers never shift to zero

-1 >> 1 is still -1, because the sign bit is copied in from the left. A loop like while n: with n >>= 1 runs forever on a negative input. NeetCode's while n > 0 avoids this. If a problem hands you a negative and says "treat it as 32-bit unsigned", first do n &= 0xFFFFFFFF.

Masks: 1 << k selects bit k

A mask is a number whose bits are chosen so that an operator touches only the positions you want. The most useful mask is 1 << k: a single 1 in box k, zeros everywhere else. OR with it to turn bit k on. AND with its NOT to turn bit k off. AND with it to ask whether bit k is on. XOR with it to flip bit k.

def get_bit(n, k):            # 1 or 0: is bit k on?
    return (n >> k) & 1

def set_bit(n, k):            # turn bit k on   (OR with the mask)
    return n | (1 << k)

def clear_bit(n, k):          # turn bit k off  (AND with the flipped mask)
    return n & ~(1 << k)

def toggle_bit(n, k):         # flip bit k      (XOR with the mask)
    return n ^ (1 << k)

get_bit(23, 3)     # 0    10111: bit 3 is the 8s box, it is off
set_bit(23, 3)     # 31   11111
clear_bit(23, 0)   # 22   10110
toggle_bit(31, 3)  # 23   back to 10111
16 8 4 2 1 n = 23 1 0 1 1 1 1 << 3 0 1 0 0 0 the mask: one 1, in box 3 OR n | mask = 31 1 1 1 1 1 only box 3 changed
A mask lets one operator touch one box. OR with 1 << 3 turns the 8s box on and leaves every other box exactly as it was, because x | 0 = x. The same idea with AND and ~mask clears the box, because x & 1 = x everywhere except the one 0.
Keep in mind

n & 1 is the mask 1 << 0. It answers "is n odd?" in one operation, because odd numbers always have their 1s box on. 23 & 1 is 1 (odd); 22 & 1 is 0 (even).

5Four moves that solve most bit problems

The lesson gives you the operators. Interviews ask for these four moves built from them. Each one is short enough to write from memory.

Move 1: Count the set bits

Two versions. The first is the lesson's n & 1 loop: it visits every bit. The second is Kernighan's trick: n & (n - 1) clears the lowest set bit, so the loop runs once per 1 bit and skips the 0s. Both are fine; the second is what you say when the interviewer asks "can you do better?".

def countBits(n):                 # visit every bit: O(number of bits)
    count = 0
    while n > 0:
        count += n & 1            # adds 1 or 0, same as the if in section 3
        n >>= 1
    return count

def countBitsKernighan(n):        # visit only the 1 bits: O(number of 1s)
    count = 0
    while n:
        n &= n - 1                # erase the lowest 1
        count += 1
    return count

countBitsKernighan(23)   # 4: 10111 → 10110 → 10100 → 10000 → 00000

Why does n - 1 do that? Subtracting 1 borrows from the lowest 1: that 1 becomes 0 and every 0 to its right becomes 1. Everything to the left is untouched. AND-ing the two numbers keeps the untouched left part and zeroes the rest.

16 8 4 2 1 n = 22 1 0 1 1 0 lowest 1 is in the 2s box n - 1 = 21 1 0 1 0 1 that 1 and everything right of it flipped AND n & (n-1) = 20 1 0 1 0 0 10110 → 10100: one 1 erased the 16 and 4 boxes agree in both rows, so AND keeps them; the flipped tail is 1 in one row and 0 in the other, so AND zeroes it
n & (n - 1) erases exactly one 1: the lowest one. Repeat until n is 0 and the number of repeats is the popcount. For 22 that is 3 turns: 10110 → 10100 → 10000 → 00000. If it takes exactly one turn, n had one 1 bit, which is Move 4.

Move 2: XOR cancels pairs

Two facts from the truth table: x ^ x = 0 (a number XOR itself is nothing) and x ^ 0 = x (XOR with nothing changes nothing). XOR is also commutative, so order does not matter. XOR a whole array together and every value that appears twice cancels itself out. Whatever appears once is left over. That solves "Single Number" with no hash map and O(1) extra space.

def singleNumber(nums):
    result = 0
    for x in nums:
        result ^= x        # pairs cancel to 0, the loner survives
    return result

singleNumber([4, 1, 2, 1, 2])   # 4

def missingNumber(nums):     # nums holds 0..n with one missing
    result = len(nums)       # start with n, the index that has no slot
    for i, x in enumerate(nums):
        result ^= i ^ x      # every present number meets its own index and cancels
    return result

missingNumber([3, 0, 1])   # 2
1 ^ 1 = 0 no partner 4 1 2 1 2 2 ^ 2 = 0 running ^ 4 5 7 6 4 = answer
Pairs vanish, the loner remains. The running value wanders (4, 5, 7, 6) but the second 1 undoes the first 1 and the second 2 undoes the first 2, so only 4 is left at the end. This needs every other value to appear an even number of times. Three copies do not cancel; that is LeetCode 137 and needs a different trick.

Move 3: An integer is a set (bitmask)

If you have at most 20 or so items, one int can be the whole set: bit i on means "item i is in". Then set union is |, intersection is &, membership is (mask >> i) & 1, and the numbers 0 to 2n - 1 are all the subsets. This replaces the backtracking subsets generator with a plain for loop, and it is how DP over subsets stores its state.

def subsets_by_mask(items):
    n = len(items)
    out = []
    for mask in range(1 << n):                        # 0 .. 2**n - 1, every subset once
        sub = [items[i] for i in range(n) if mask >> i & 1]  # bit i on → items[i] is in
        out.append(sub)
    return out

subsets_by_mask(["a", "b", "c"])   # 8 subsets, mask 0b101 → ['a', 'c']

A = 0b0110          # {1, 2}
B = 0b0011          # {0, 1}
A | B               # 0b0111  union {0, 1, 2}
A & B               # 0b0010  intersection {1}
A & ~B              # 0b0100  difference {2}
(A >> 2) & 1        # 1       is 2 in A? yes
maskc b a (bit 2, bit 1, bit 0)Subset of ["a", "b", "c"]
0000[]
1001["a"]
2010["b"]
3011["a", "b"]
4100["c"]
5101["a", "c"]
6110["b", "c"]
7111["a", "b", "c"]

Move 4: Power of two in one line

A power of two has exactly one 1 bit: 1, 10, 100, 1000. Move 1 said n & (n - 1) erases the lowest 1. If erasing one 1 leaves zero, there was only one. Guard against n = 0, which also gives 0 but is not a power of two, and against negatives.

def isPowerOfTwo(n):
    return n > 0 and n & (n - 1) == 0

isPowerOfTwo(16)   # True   10000 & 01111 = 00000
isPowerOfTwo(12)   # False  01100 & 01011 = 01000
isPowerOfTwo(0)    # False  the n > 0 guard

6Big-O summary

Bit operations are the fastest thing a CPU does: one instruction each on a fixed-width int. The loops cost as many turns as there are bits, and a number n has about log2(n) bits, so "per bit" is O(log n), not O(n).

OperationTimeExtra spaceNote
& | ^ ~ << >> on one intO(1)*O(1)* on a 32/64-bit int; Python big ints cost O(number of bits)
countBits with n & 1 and >>O(log n)O(1)one turn per bit; 32 turns for a 32-bit int
Kernighan n &= n - 1O(k)O(1)k = number of 1 bits; never worse than the loop above
n.bit_count()O(1)*O(1)one CPU popcount instruction on fixed-width ints
XOR over an array (single number)O(n)O(1)the hash-set version is O(n) space
Test / set / clear one bit with a maskO(1)O(1)
Enumerate all subsets by maskO(2n · n)O(1) per masksame count as backtracking, but no recursion
Power-of-two checkO(1)O(1)vs. O(log n) for a divide-by-2 loop

7Mistakes to watch for

Using ^ for power

2 ^ 3 is 1 (XOR of 010 and 011), not 8. Power in Python is 2 ** 3. This is the most common bit bug in code written by people who never use bits.

Shift next to plus without parentheses

1 << k + 1 is 1 << (k + 1), because + binds tighter than <<. Write (1 << k) + 1. Same for -: n & n - 1 works only because - also binds tighter than &; write n & (n - 1) anyway so the reader does not have to think.

Right-shifting a negative and waiting for zero

-1 >> 1 is -1 forever, so while n: n >>= 1 never ends. Use while n > 0 as the lesson does, or mask to 32 bits first with n &= 0xFFFFFFFF.

Expecting ~n to give a small positive number

~1 is -2, not 0. Python has no fixed width, so NOT flips infinitely many bits and the result is -n - 1. To "flip the low 8 bits only" write n ^ 0xFF (or ~n & 0xFF).

Counting bits from the wrong end

Bit 0 is the rightmost box, worth 1. "The 3rd bit" is ambiguous; say "bit 3" and mean 1 << 3 = 8. In format(n, "08b") the string index 0 is bit 7, the opposite direction.

XOR trick on the wrong input

singleNumber works only if every other value appears an even number of times. With three copies (LeetCode 137) or two singles (LeetCode 260) the plain XOR gives garbage. Check the problem statement before you reach for it.

Power of two without the n > 0 guard

0 & -1 == 0, so n & (n - 1) == 0 says 0 is a power of two. It is not. Always n > 0 and ....

Forgetting the 32-bit mask when the problem says 32-bit

Reverse Bits and Sum of Two Integers assume a 32-bit int. In Python a carry can climb past bit 31 forever. Mask with 0xFFFFFFFF after every step, and convert back to a signed value at the end if the top bit is set.

Only knowing the built-in

bin(n).count("1") is fine in production. In an interview, write the loop first, then say "in Python I would use bit_count()". The loop is what they are testing.

Interview one-liners

  • "Each bit position is a power of two, so n >> 1 is n // 2 and n << 1 is n * 2."
  • "n & 1 reads the lowest bit; it tells me odd or even in O(1)."
  • "n & (n - 1) clears the lowest set bit, so I can count 1s in O(number of 1s) or test for a power of two in one line."
  • "XOR is its own inverse: x ^ x = 0 and x ^ 0 = x, so XOR-ing an array cancels every pair and leaves the single number, O(n) time, O(1) space."
  • "1 << k is a mask for bit k: OR sets it, AND with the NOT clears it, AND tests it."
  • "An int can be a set of up to 63 items; range(1 << n) enumerates every subset."
  • "Python ints never overflow, so for 32-bit problems I mask with 0xFFFFFFFF; and ~n is -n - 1."

8Practice, in this order

Each of these is a five-line function once you see the trick. The point is to see the trick fast. Do them with no notes open, then compare with the moves above.

#ProblemMove it trainsLevel
191Number of 1 Bitsn & 1 loop, then KernighanEasy
231Power of Twon & (n - 1) == 0 with the n > 0 guardEasy
136Single NumberXOR cancels pairsEasy
268Missing NumberXOR values against indexesEasy
461Hamming DistanceXOR then count bitsEasy
338Counting Bitsdp[i] = dp[i >> 1] + (i & 1), DP meets bitsEasy
190Reverse Bitsread bit i with a mask, write bit 31 - i, 32 turnsEasy
78Subsetsbitmask enumeration instead of backtrackingMedium
371Sum of Two IntegersXOR is add-without-carry, AND << 1 is the carry, 32-bit maskMedium
137Single Number IIcount each bit position mod 3 (XOR alone is not enough)Medium

Your next step today: LeetCode 191. Write the n & 1 loop from memory, run it on 23 and check you get 4, then rewrite it with n &= n - 1 and check again.

9Self-check

Answer out loud before opening. If you cannot answer in one breath, reread that section.

Q1What is 10111 in decimal, and how did you get it?

23. Read the place values of the 1s from the right: 1 + 2 + 4 + 16 = 23. The 8s box is 0, so skip it.

Q2Give the one row of each truth table that makes it different from the others.

AND: only 1 & 1 gives 1. OR: only 0 | 0 gives 0. XOR: 1 ^ 1 gives 0 (same inputs cancel). NOT has one input and flips it.

Q3What does n >> 1 compute, and what happens to the lowest bit?

n // 2. Every bit slides one box to the right, so every place value halves. The bit in the 1s box falls off; it was the remainder of the division.

Q4Shift 001 left three times in a 3-bit register. What are the three results and why is the last one surprising?

010, 100, 000. The 1 falls off the left edge in the last step, so 4 doubled becomes 0 instead of 8. Python ints would give 8 because they have no fixed width.

Q5Why does n & 1 tell you whether the lowest bit is on?

1 is ...0001: only bit 0 is set. AND gives 1 only where both inputs are 1, so every other position becomes 0 and bit 0 keeps its value. The result is 1 if bit 0 was 1, else 0. Same test tells you odd or even.

Q6Trace it: run countBits(10). Give n, n & 1 and count after each turn.

10 is 1010. Turn 1: n=1010, n&1=0, count=0, shift → 101. Turn 2: n=101, n&1=1, count=1, shift → 10. Turn 3: n=10, n&1=0, count=1, shift → 1. Turn 4: n=1, n&1=1, count=2, shift → 0. Loop ends. Answer 2.

Q7What does n & (n - 1) do, and why?

It clears the lowest set bit. Subtracting 1 turns the lowest 1 into 0 and all 0s to its right into 1s, leaving higher bits alone. AND keeps the untouched higher bits and zeroes the flipped tail. 22 (10110) becomes 20 (10100).

Q8Trace it: count the 1s in 12 using Kernighan's loop. Show n after each n &= n - 1.

12 is 1100. Turn 1: 1100 & 1011 = 1000 (8), count 1. Turn 2: 1000 & 0111 = 0000, count 2. n is 0, stop. Answer 2, in 2 turns instead of 4.

Q9Why does XOR-ing [4, 1, 2, 1, 2] give 4?

x ^ x = 0 and x ^ 0 = x, and order does not matter. So the two 1s cancel, the two 2s cancel, and 4 ^ 0 ^ 0 = 4. Running values: 4, 5, 7, 6, 4.

Q10Write the expressions to set, clear and test bit k of n.

Set: n | (1 << k). Clear: n & ~(1 << k). Test: (n >> k) & 1 (or n & (1 << k) != 0). Toggle: n ^ (1 << k).

Q11Why is ~1 equal to -2 in Python and not 0?

Python ints have no fixed width. NOT flips every bit including infinitely many leading zeros, which in two's complement is the number -n - 1. To flip only the low 8 bits use n ^ 0xFF.

Q12How do you check "is n a power of two" in O(1), and which input needs a guard?

n > 0 and n & (n - 1) == 0. A power of two has exactly one 1 bit, so clearing the lowest 1 leaves 0. The guard is for n = 0, where 0 & -1 is also 0 but 0 is not a power of two.