Bit Manipulation
Every int is 32 switches. Learn six moves and a whole family of problems becomes one line.
▶ guided lesson⚡ 1-minute summary↻ 14 recall cards
before this: Big-O · Java Toolkit · Hashing · Backtracking
01 · why it exists
Why this exists, and the weight it carries
since1945
Two's complement integers
John von Neumann (EDVAC report); the EDSAC team at Cambridge
In his June 1945 "First Draft of a Report on the EDVAC", von Neumann stored a negative number through the complements of its digits, working modulo a power of two. To subtract, every digit is replaced by its complement and one unit is added in the last place — what we now call two's complement. Cambridge's EDSAC (1949) stored its numbers in two's complement too. Java's language spec fixes it for good: every int is a 32-bit signed two's-complement integer.
the problem it solvedOne adder for both addition and subtraction, and a single zero, instead of separate sign handling.
its jobs today
- Every Java
byte,short,intandlongis stored this way (JLS §4.2), so one adder circuit handles +, − and negative numbers alike. - Wrap-around you can rely on:
Integer.MAX_VALUE + 1 == Integer.MIN_VALUE, which hash functions and checksums depend on.
the weight it carries
Illustrative: 32 bits give 2³² = 4,294,967,296 patterns. Two's complement spends them on −2,147,483,648 … 2,147,483,647: exactly one zero, and one more negative than positive. That spare negative is why Math.abs(Integer.MIN_VALUE) is still negative.
without it
With sign-and-magnitude there would be two zeros (+0 and −0), and the CPU would need separate circuits to subtract and to compare signed numbers.
when · why · how
- when
- Whenever negative numbers meet bit operators:
>>vs>>>,x & -x, overflow checks,Integer.MIN_VALUEedge cases. - why
- Bit 31 counts as −2³¹ and −x = ~x + 1. Knowing that turns negative-number bit tricks from magic into arithmetic.
- how
Integer.toBinaryString(-1)shows 32 ones; use>>>to treat the bits as unsigned;Integer.toUnsignedLong(x)reads them as 0 … 2³² − 1.
since1950s–1977
Bitmasks as sets (and bitboards)
R. J. Walker; the Soviet team that later built Kaissa; David Slate & Larry Atkin (Chess 4.x)
As Knuth tells it, R. J. Walker's 1950s n-queens program already kept the attacked columns and diagonals as bit vectors. Chess programs turned the idea into bitboards: one 64-bit word per piece type, one bit per square. Community histories credit the Soviet group that later built Kaissa (Adelson-Velsky, Arlazarov and colleagues, late 1960s) and Northwestern University's Chess 4.x, described by Slate and Atkin in 1977.
the problem it solvedAnswering "which squares are attacked?" for a whole board with a few word-wide operations instead of a loop over 64 squares.
its jobs today
- Java's
EnumSetstores a set of up to 64 enum constants as the bits of onelong, socontainsis a single AND. - Permissions and feature flags: Unix
rwxis three bits, and checking access is one AND. - Chess engines keep one 64-bit
longper piece type — one bit per square — so whole-board questions are a few shifts and ANDs.
the weight it carries
Illustrative: a chessboard has 64 squares — exactly one long. "Is any square a knight can reach attacked?" over two boolean[64] arrays is up to 64 checks; over two bitboards it is one AND of 8-byte numbers.
without it
Small sets would be HashSet<Integer>s of boxed numbers: many times the memory, and union or intersection would loop element by element instead of taking one instruction.
when · why · how
- when
- The universe of items is small and fixed: ≤ 32 (int), ≤ 64 (long), letters a–z, visited nodes in bitmask DP, enum options.
- why
- Add, remove, contains, union and intersection are each one O(1) operator, and the whole set is one number you can use as a map key or DP index.
- how
mask | (1 << i)add ·mask & ~(1 << i)remove ·(mask & (1 << i)) != 0contains ·Integer.bitCount(mask)size. UseEnumSetfor named options andBitSetbeyond 64 items.
since1960
Clearing the lowest 1-bit: x & (x − 1)
Peter Wegner (first published); D. H. Lehmer (independently); made famous by Kernighan & Ritchie
Peter Wegner published the trick in 1960 in a one-page note, "A technique for counting ones in a binary computer" (Communications of the ACM). D. H. Lehmer found it independently and published it in 1964, as Knuth later remarked. Kernighan and Ritchie spread it as exercise 2-9 of "The C Programming Language" (it is in the 1988 second edition): x & (x − 1) deletes the rightmost 1-bit — explain why. That's why many people call it "Kernighan's trick", though he didn't invent it.
the problem it solvedCounting the 1-bits of a word in as many steps as there are 1s, instead of one step per bit.
its jobs today
- Popcount (
Integer.bitCount): Hamming distance between two hashes, counting set flags, sizing a bitmask set. - Power-of-two checks: OpenJDK's
Random.nextInt(bound)tests(bound & (bound − 1)) == 0and takes a faster path when the bound is a power of two. - Walking the set bits of a mask one by one (
free &= free - 1), as in N-Queens II and Sudoku.
the weight it carries
Illustrative: count the 1-bits of 10 lakh (1,000,000) ints that have about 3 ones each. Checking all 32 positions: 32 × 1,000,000 = 3.2·10⁷ steps. Clearing one 1-bit per step: about 3 × 1,000,000 = 3·10⁶ steps — roughly 10× fewer.
without it
Every popcount would loop over all 32 (or 64) bits, and a power-of-two test would need a division loop.
when · why · how
- when
- Count 1-bits, test for a power of two, or visit the set bits of a mask one at a time.
- why
- x − 1 flips the lowest 1 and every 0 below it, so the AND clears exactly that bit: O(number of 1-bits) instead of O(32).
- how
while (x != 0) { x &= x - 1; count++; }· power of two:x > 0 && (x & (x - 1)) == 0· in production:Integer.bitCount(x).
since?
XOR cancellation (parity)
XOR comes from Boolean logic, and the "pairs cancel" trick has no single inventor — it is simply a ^ a = 0 put to work.
its jobs today
- Storage parity (RAID 5): the parity block is the XOR of the data blocks, so one lost block is rebuilt as the XOR of all the others.
- Error detection: a parity bit (the XOR of all the bits) catches any single flipped bit in a byte sent over a wire.
- Hash mixing: OpenJDK's HashMap computes
h ^ (h >>> 16)so the high bits of a hash also affect which bucket it lands in.
the weight it carries
Illustrative: find the one unpaired id among 10 lakh (1,000,000) order ids. A HashSet can hold up to 500,000 boxed Integers at once — roughly 48 bytes each with its map entry, about 24 MB. The XOR fold uses one 4-byte int.
without it
Finding the odd one out would need O(n) extra memory (a set or a count map) instead of a single int.
when · why · how
- when
- Everything comes in pairs except one or two; numbers 0..n with one missing; parity and checksum questions.
- why
- a ^ a = 0 and a ^ 0 = a, in any order — so one pass with one int cancels every pair: O(n) time, O(1) space.
- how
int x = 0; for (int v : nums) x ^= v;For two singles, split the numbers bydiff = x & -x.
since1937–38
Binary addition: sum bit and carry
Claude E. Shannon
As an MIT master's student (thesis written in 1937, degree awarded in 1940), Claude Shannon showed that Boolean algebra can design relay and switching circuits. His 1938 paper "A Symbolic Analysis of Relay and Switching Circuits" includes an "electric adder to the base two", built only from relays and switches. He picked base two because it makes the circuit far simpler. A CPU's adder still works out a sum bit and a carry bit for every column.
the problem it solvedDoing arithmetic with switches: turning "add two numbers" into a circuit of on/off logic.
its jobs today
- Every CPU's adder: sum bit = a ^ b ^ carry, carry = "at least two of the three are 1" — the same rules as Sum of Two Integers.
- Big numbers:
BigIntegeradds numbers wider than a machine word piece by piece with a carry, just as Add Binary does digit by digit.
the weight it carries
Illustrative: two 10,000-digit binary strings. Column by column: at most 10,001 steps. Converting them to a long instead fails beyond 63 digits — 9,937 digits short.
without it
No way to add numbers wider than the machine word: no BigInteger, no 2048-bit cryptography keys.
when · why · how
- when
- Numbers given as strings or digit lists (binary or decimal), or "add without + or −".
- why
- Each column needs only its two digits and the carry, so one right-to-left pass is O(n) for any length.
- how
- Two indices from the right, an
int carry, aStringBuilder:sum = carry + da + db; sb.append(sum % 2); carry = sum / 2;thensb.reverse(). Without +:carry = (a & b) << 1; a ^= b; b = carry;.
02 · plain english
The idea in 30 seconds
A Java int is a row of 32 bits. Operators like &, |, ^ and shifts act on all 32 at once, in one CPU step.
With a mask (1 << k) you can read, set, clear or flip any single bit in O(1).
Two facts unlock most interview problems: a ^ a = 0 (pairs cancel) and x & (x − 1) erases the lowest 1-bit.
picture this
An int is like an app's Settings → Permissions screen with 32 toggles. A mask names the toggles you care about: OR switches them on, AND-NOT switches them off, XOR flips them, and AND tells you which ones are on.
03 · remember
What you must know
- Java
int= 32 bits in two's complement. Bit 31 is the sign bit. Range is −2³¹ … 2³¹−1, and-x == ~x + 1. - The operators:
&(both 1),|(either 1),^(different),~(flip all),<<(shift left, ×2),>>(shift right, copies the sign bit),>>>(shift right, fills with 0). - With
mask = 1 << k: check(x >> k) & 1, setx | mask, clearx & ~mask, togglex ^ mask. x & (x − 1)erases the lowest 1-bit. Son > 0 && (n & (n − 1)) == 0means "power of two", and looping it counts 1-bits.x & -xkeeps only the lowest 1-bit (e.g. 12 = 1100 → 4 = 0100). It splits numbers into two groups in Single Number III.- XOR rules:
a ^ a = 0,a ^ 0 = a, and order does not matter. XOR a whole array and every pair cancels. - An int is also a set of the numbers 0–31 (bit i on = i is in the set). Counting
maskfrom 0 to 2ⁿ − 1 visits every subset of n items. - Bit operations are O(1) on a fixed-width word. A loop over the bits of a value V is O(log V), which is at most 32 steps for an
int.
04 · see it
Play with it in 3D
Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.
Check, set, clear, toggle on 8 bits
The mask lights up bit k. Watch which bits each operator touches, and which it leaves alone.
>> vs >>> on a negative number
Both slide bits right. `>>` copies the sign bit into the gap. `>>>` always fills it with 0.
Count 1-bits with n & (n − 1)
Each step erases exactly one 1-bit, so the loop runs once per 1-bit instead of 32 times.
XOR fold: pairs cancel
Each number flips some bits of x. A number seen twice flips the same bits back, so only the loner is left.
Counting Bits: a DP built from i >> 1
i and i >> 1 have the same bits except the last one, so ans[i] = ans[i >> 1] + (i & 1).
Every subset is a number
Bit i of the mask says "take nums[i]". Counting 0, 1, 2, … lists every subset exactly once.
Binary addition, column by column
Each column adds two digits and the carry: write sum % 2, carry sum / 2. A CPU's adder follows the same two rules.
05 · cost
Time & space, explained
| Time | why | |
|---|---|---|
&, |, ^, ~, <<, >>, >>> | O(1) | One CPU instruction that works on all 32 (or 64) bits in parallel. |
| Check / set / clear / toggle bit k | O(1) | One shift to build the mask plus one operator. |
Integer.bitCount, numberOfTrailingZeros, highestOneBit | O(1) | Fixed-width tricks on one word. bitCount is a HotSpot intrinsic: it may compile to one POPCNT instruction on x86-64 CPUs that have it. |
Count 1-bits with n &= n − 1 | O(k), k = number of 1-bits | Each loop erases one 1-bit. At most 32 for an int. |
| Loop over every bit of a value V | O(log V) | V has about log₂V bits. For an int that is at most 32 steps, so O(1) in practice. |
| Enumerate all subsets of n items with masks | O(n · 2ⁿ) | 2ⁿ masks, and building each subset checks n bits. n ≈ 20 is the practical limit (about 2·10⁷ steps). |
| Enumerate every submask of every mask | O(3ⁿ) | Each item is in neither, only the mask, or both. That gives 3 choices per item. |
| Time | Extra space | why | |
|---|---|---|---|
| Find the unpaired number: HashSet | O(n) | O(n) | Stores up to n/2 values that are still waiting for a partner. |
| Find the unpaired number: XOR fold | O(n) | O(1) | One int accumulator. Pairs cancel to 0. |
Set of small ints (≤ 64): long mask | O(1) per op | 8 bytes | Add, remove, contains, union and intersect are each one operator. |
Set of ints 0…n−1: boolean[n] | O(1) per op | ~n bytes | The JVM typically uses one byte per boolean. |
Set of ints 0…n−1: BitSet | O(1) per op | ~n/8 bytes | One bit per number, packed into a long[]. cardinality() is O(n/64). |
06 · java
Raw vs Collections Framework
One bit at a time: raw operators vs Integer helpers
class BitOps { // k is the bit position: 0 = rightmost (least significant) bit. static boolean isSet(int x, int k) { return ((x >> k) & 1) == 1; } static int set(int x, int k) { return x | (1 << k); } static int clear(int x, int k) { return x & ~(1 << k); } static int toggle(int x, int k) { return x ^ (1 << k); } static int dropLowest(int x) { return x & (x - 1); } static int lowestBit(int x) { return x & -x; }}class Library { static int ones(int x) { return Integer.bitCount(x); } static int highest(int x) { return Integer.highestOneBit(x); } static int lowest(int x) { return Integer.lowestOneBit(x); } static int trailingZeros(int x) { return Integer.numberOfTrailingZeros(x); } static int leadingZeros(int x) { return Integer.numberOfLeadingZeros(x); } static int reversed(int x) { return Integer.reverse(x); } static String binary(int x) { return Integer.toBinaryString(x); } static String padded8(int x) { return String.format("%8s", Integer.toBinaryString(x & 0xFF)).replace(' ', '0'); } static long asUnsigned(int x) { return Integer.toUnsignedLong(x); }}- Write the raw operators when the trick is the question (Power of Two, Number of 1 Bits). Interviewers want to see
n & (n − 1). - Use
Integer.bitCount,numberOfTrailingZerosand similar helpers when bits are only a step. They are tested and fast, and every one has aLong.twin. Integer.toBinaryStringdrops leading zeros for positive numbers. Pad withString.format("%32s", …).replace(' ', '0')when debugging.- Java has no
unsigned int. When you need to read the bits as unsigned, use>>>,Integer.toUnsignedLong,Integer.toUnsignedStringorInteger.parseUnsignedInt.
A set of small numbers: int mask vs BitSet
class MaskSet { int mask = 0; // bit i is 1 <=> i is in the set (0 <= i < 32) void add(int i) { mask |= 1 << i; } void remove(int i) { mask &= ~(1 << i); } boolean contains(int i) { return (mask & (1 << i)) != 0; } int size() { return Integer.bitCount(mask); } int union(int other) { return mask | other; } int intersect(int other) { return mask & other; }}class Sieve { /** Primes up to n, one bit per number instead of one byte per boolean. */ static BitSet primesUpTo(int n) { BitSet composite = new BitSet(n + 1); BitSet primes = new BitSet(n + 1); for (int i = 2; i <= n; i++) { if (composite.get(i)) continue; primes.set(i); for (long j = (long) i * i; j <= n; j += i) composite.set((int) j); } return primes; }}- An
intholds a set of 0–31 and alongholds 0–63. Union is|, intersection is&, and size isbitCount. Masks also make good HashMap keys and DP indices. BitSetgrows to any size and stores one bit per number in along[], so it is 8× smaller thanboolean[]. It hasand,or,xor,andNot,cardinalityandnextSetBit.EnumSetis the same idea for enums. For enums with up to 64 constants it is backed by a singlelong(RegularEnumSet).
Shifts: >>, >>> and <<
class Shifts { static int arithmetic(int x, int k) { return x >> k; } // copies the sign bit in static int logical(int x, int k) { return x >>> k; } // always fills with 0s static int left(int x, int k) { return x << k; } // k is taken mod 32!}>>is an arithmetic shift. It copies the sign bit, so-16 >> 2 == -4, which is division by 4 rounded toward −∞.>>>is a logical shift. It always fills with 0, so-1 >>> 31 == 1. Use it whenever you treat an int as 32 raw bits.- The shift distance is taken mod 32 for
int(mod 64 forlong). So1 << 32 == 1, not 0. Write1L << kwhen k can be 31 or more. byte,shortandcharare promoted tointbefore shifting. Mask withb & 0xFFto get the unsigned value of a byte.
| call | does | cost |
|---|---|---|
Integer.bitCount(x) / Long.bitCount(x) | Number of 1-bits (popcount) | O(1) |
Integer.highestOneBit(x) | Only the highest 1-bit kept (0 for 0). 12 → 8 | O(1) |
Integer.lowestOneBit(x) | Only the lowest 1-bit kept, same as x & -x. 12 → 4 | O(1) |
Integer.numberOfTrailingZeros(x) | Index of the lowest 1-bit (32 for 0) | O(1) |
Integer.numberOfLeadingZeros(x) | Zeros before the highest 1-bit. 31 − nlz(x) = floor(log₂ x) | O(1) |
Integer.reverse(x) | Reverse all 32 bits | O(1) |
Integer.toBinaryString(x) | Binary text without leading zeros (negatives show all 32 bits) | O(32) |
Integer.parseUnsignedInt(s, 2) | Parse 32 binary digits even when the first one is 1 | O(len) |
Integer.toUnsignedLong(x) | Read the bits of x as 0 … 2³²−1 | O(1) |
new BitSet(n); set / get / clear / flip(i) | Growable bit array, one bit per index | O(1) each |
bitSet.cardinality() / nextSetBit(i) | Count the 1s / find the next 1 at or after i | O(n/64) |
A set of at most 32 (or 64) small values, e.g. visited cities, letters a–z
→ int / long mask
O(1) set operations, and the mask itself can be a DP index or map key.
A large set of flags over 0…n−1 (a sieve, a visited array)
→ BitSet
8× less memory than boolean[] and fast bulk and/or.
Count, find or reverse bits as a helper step
→ Integer.bitCount / numberOfTrailingZeros / reverse
Correct on every edge case (0, negatives) and usually compiled to single instructions.
The interviewer asks how it works
→ Raw operators
n & (n − 1), x & -x and the XOR fold are what is being tested.
A fixed set of named options (permissions, features)
→ EnumSet
Bitmask speed with readable names and type safety.
07 · recognise
Spot the pattern
"Every element appears twice except one"
XOR everything: pairs cancel
"…appears three times except one"
Count each bit position mod 3 (or the ones/twos state machine)
Numbers are exactly 0…n with one missing / one duplicated, O(1) space
XOR values with indices (or the Gauss sum)
"Without using + / - / *"
XOR = add without carry, (a & b) << 1 = the carries; shifts multiply by 2
"Power of two", "number of 1 bits", "binary representation"
n & (n − 1), Integer.bitCount
n ≤ ~20 and "all subsets" / "try every combination"
Loop mask from 0 to 2ⁿ − 1
State is a small set (visited nodes ≤ 16, letters a–z)
Store the set in an int mask, often as a DP dimension (bitmask DP)
08 · traps & tricks
Mistakes to avoid, tricks to use
traps
- Precedence:
==binds tighter than&, sox & 1 == 0does not even compile in Java. Also1 << k - 1means1 << (k − 1). Always add parentheses:(x & 1) == 0. 1 << kis anint.1 << 31is negative and1 << 32 == 1. Use1L << kfor long masks.- Using
>>in a loop likewhile (n != 0) n >>= 1;never ends for a negative n, because it sticks at −1. Use>>>. - Testing a bit with
(x & mask) == 1only works for bit 0. Write(x & mask) != 0. Math.abs(Integer.MIN_VALUE)and-Integer.MIN_VALUEare both stillInteger.MIN_VALUE. Two's complement has one more negative than positive.Integer.parseInt(bits, 2)throws when 32 digits start with 1. UseInteger.parseUnsignedInt.- Forgetting
n > 0in the power-of-two test. Both 0 andInteger.MIN_VALUEpass(n & (n − 1)) == 0.
tricks
- Simple hai — memorise six moves: check, set, clear, toggle,
x & (x − 1)andx & -x. Almost every bit problem combines them. - Work examples on paper with 4-bit numbers (0–15). The patterns are the same as with 32 bits, and you can see them.
- Say the identity out loud in interviews: "XOR is addition without carry, and
a ^ a = 0, so pairs cancel." - Always test 0, 1, −1,
Integer.MIN_VALUEandInteger.MAX_VALUE. These are where bit code breaks. - Write the raw version first, then mention the library call (
Integer.bitCount). This shows you know both. - If the input size is around 20 and the problem says "choose any subset", reach for masks before recursion.
09 · why & how
Questions you might be too shy to ask
How do I read a binary number, and which one is "bit 0"?
Bit 0 is the rightmost bit and is worth 1. Bit 1 is worth 2, bit 2 is worth 4: bit k is worth 2ᵏ. So 1011 = 8 + 0 + 2 + 1 = 11. When a problem says "bit k", count from the right, starting at 0. 1 << k is exactly the number with only bit k on.
Isn't ^ the power operator? And is & the same as &&?
No to both, dhyan do. In Java ^ is XOR: 2 ^ 3 is 1 (10 XOR 11 = 01), not 8. For powers of two write 1 << 3; for anything else, Math.pow (it returns a double). & on ints works bit by bit: 6 & 3 is 2. && works only on booleans and stops early when the left side is false.
How are negative numbers stored, and why is −x = ~x + 1?
Java uses two's complement. Bit 31 counts as −2³¹ instead of +2³¹, and the other bits count as usual. So −1 is all 1s (−2³¹ + 2³¹ − 1). x + ~x is always all 1s, which is −1. Rearranged, that gives -x == ~x + 1.
To check odd or even, should I write x % 2 == 1 or (x & 1) == 1?
Use (x & 1) == 1 (or x % 2 != 0). In Java, % keeps the sign of the left side, so -3 % 2 is −1, and x % 2 == 1 wrongly calls −3 even. Bit 0 is 1 for every odd number, negative ones too, so (-3 & 1) is 1.
Why does Java have >>> when C and C++ don't?
Java has no unsigned int or long (only char is unsigned), so it needs a separate operator for "shift and fill with zeros". C picks the shift type from whether the variable is signed or unsigned. Java picks it from the operator: >> keeps the sign and >>> doesn't.
Why does x & (x − 1) erase exactly the lowest 1-bit? Show me on a number.
Take x = 12 = 1100. Subtracting 1 borrows from the lowest 1: that bit becomes 0 and every 0 below it becomes 1, so x − 1 = 1011. The bits above stay the same. AND keeps only the bits both share: 1100 & 1011 = 1000 = 8. One 1-bit gone, simple hai.
And why does x & -x keep only the lowest 1-bit?
-x is ~x + 1. For 12: x = 0000 1100, ~x = 1111 0011, and +1 carries into the first 0, giving 1111 0100. Above the lowest 1-bit, -x is the exact opposite of x; at that bit both have a 1; below it both are 0. So the AND leaves 0000 0100 = 4.
Why does XOR-ing the whole array work even though pairs are not next to each other?
XOR is commutative and associative, so you can reorder the terms freely. In your head, move each pair together: a ^ a = 0, and 0 ^ x = x. Only the unpaired value is left. The order in the array never matters.
Is bit manipulation actually faster, or just a party trick?
Single operations are as cheap as +. The big wins are elsewhere: O(1) space (XOR fold instead of a HashSet), packing 64 flags into one long, and bulk operations (BitSet.and works on 64 flags at a time, one long word per step). Don't write x >> 1 instead of x / 2 for speed. The JIT compiler already makes division by 2 fast, and the two differ for negative numbers: -3 / 2 is −1 but -3 >> 1 is −2.
When do I use int, long, or BitSet for a mask?
Up to 31 items → int. Up to 63 → long (with 1L << i). More than that, or a size known only at runtime → BitSet or boolean[]. For bitmask DP the limit is really the 2ⁿ table: n ≈ 20 is the most you can afford.
How do I see the binary of a number while debugging?
String.format("%32s", Integer.toBinaryString(x)).replace(' ', '0') prints all 32 bits with leading zeros. Integer.toBinaryString alone hides the leading zeros of positive numbers.
Single Number II: the ones/twos trick makes no sense to me. Do I need it?
Not to pass. The 32-column count is also O(n) time and O(1) space, and you can explain every line of it. A negative answer needs no special case: at bit 31, result |= 1 << bit is 1 << 31, which turns on the sign bit, so the rebuilt int is negative exactly like the single number. Learn ones/twos later, as a bonus for the follow-up.
Subsets with bitmasks or with backtracking: which should I use?
Both are O(n·2ⁿ). Masks are shorter, iterative and easy to get right. Backtracking is better when you can prune, i.e. skip whole branches (combination sum, constraints), or when n is unknown or large. Learn both. The backtracking chapter covers the other side.
Is using Integer.bitCount in an interview cheating?
It isn't cheating, but it may skip the point of the question. Say: "In production I'd use Integer.bitCount. Here's what it does underneath," and then write the n & (n − 1) loop. Interviewers love that answer.
10 · practice
Interview problems
Every problem has brute → better → optimal solutions in Java, with complexity and a dry run.
- #136
- #191
- #338
- #190Reverse BitsEasyNVIDIAAirbnbAppleAmazonMicrosoft
- #268
- #67
- #371Sum of Two IntegersMediumGoogleAmazonMetaMicrosoft
- #137Single Number IIMediumMicrosoftGoogleAmazon
- #260Single Number IIIMediumAmazonGoogle
- #231Power of TwoEasyGoogleAmazon
- #201Bitwise AND of Numbers RangeMediumGoogleAmazon
Also practise this here
Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.
- #78SubsetsMediumin Backtracking
Bitmask enumeration: the numbers 0 … 2ⁿ − 1 are exactly the in/out patterns of n elements (see its bitmask approach).
- #52N-Queens IIHardin Backtracking
Three int masks hold every attacked column;
free & -freepeels off the safe ones. - #421Maximum XOR of Two Numbers in an ArrayMediumin Tries
Greedy on bits from the top, with a binary trie: XOR again, but now maximised.
- #779K-th Symbol in GrammarMediumin Recursion
The answer is the parity of
Integer.bitCount(k − 1)— popcount in disguise.
11 · revise
The whole chapter on one screen
10 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.
- what it is
A Java
intis 32 bits in two's complement.&,|,^,~,<<,>>,>>>work on all 32 at once, in O(1). - template
With
m = 1 << k: check(x & m) != 0· setx | m· clearx & ~m· togglex ^ m. - pro tip
x & (x − 1)erases the lowest 1-bit (popcount, power of two).x & -xkeeps only the lowest 1-bit (Single Number III). - use it when
"Twice except one", "missing from 0..n", "without + or −", "power of two", "all subsets" with n ≤ 20 → think bits.
- pro tip
XOR:
a ^ a = 0,a ^ 0 = a, any order. XOR everything and every pair cancels, in O(1) space. - cost
One operator: O(1). A loop over a value's bits: O(log V) ≤ 32. All subsets by mask: O(n·2ⁿ). Every submask of every mask: O(3ⁿ).
- trap
==binds tighter than&: write(x & m) != 0. And(x & m) == 1is only right for bit 0. - trap
1 << 32 == 1(the shift is taken mod 32): use1L << kfor long masks.>>keeps the sign; use>>>for raw bits. - trap
One extra negative:
-Integer.MIN_VALUE == Integer.MIN_VALUE. A power-of-two test needsn > 0first. - pro tip
Binary numbers as long strings: add column by column from the right with a carry.
Integer.parseInt(s, 2)overflows past 31 digits.
12 · recall
Flip, remember, repeat
Why is -x == ~x + 1 in Java?
Question 1: Why is -x == ~x + 1 in Java?
13 · check yourself
Quick quiz
What is 12 & (12 − 1)?
In Java, what is -8 >>> 28?
Which expression correctly tests whether bit k of x is set?
What does XOR-ing all of [4, 1, 2, 1, 2] give?
What is the value of `1 << 32` for an int in Java?
nums = [a, b, c, d]. Which mask represents the subset {a, c}?
Why does `n > 0 && (n & (n − 1)) == 0` need the `n > 0` part?
What is the bitwise AND of every number from 12 to 15?
Add Binary: why does the loop also run while `carry > 0`?
14 · learn more
A second teacher, if you want one
- ▶ playlistBit Manipulation Playlist | Language Independent Course ↗Striver (take U forward) · EnglishOperators, 1's and 2's complement and the must-know tricks, then Single Number I–III, power set and XOR of a range.
- ▶ videoBitwise Operators + Number Systems - Maths for DSA ↗Kunal Kushwaha · EnglishNumber systems and every bitwise operator from scratch, in Java. This is the foundation all the one-line tricks rely on.
- ▶ videoBit Manipulation Algorithms Part 1 | Interview Questions Java C++ | Anuj Bhaiya ✅| DSAOne Course #2 ↗Anuj Bhaiya (Anuj Kumar Sharma) · HindiBinary basics and the common bit tricks in Hindi, with Java code. It's part 1 of a three-video series.