Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Bit Manipulation

Builds on XOR Cancel, which you haven’t finished yet.

P3MediumBuilt on XOR Cancel~3 min speedrun

Per-Bit Counting (Single Number II / Bitwise State Machine)

Built on
XOR CancelA count modulo 3 is kept for each bit, where XOR Cancel keeps one parity bit.

Single Number II (LC 137)(opens leetcode.com)

An integer array nums has every value appearing exactly three times, except for a single value that appears only once. Return that unique value.

Your solution must run in linear time and use only constant extra space.

Example 1
Input:nums = [2,2,3,2]
Output:3
2 appears three times; 3 appears once.

Per-Bit Counting

value stream âž” bit registers (ones, twos, ...) âž” survivor
Spot it when: Every value appears k times (k of 3 or more) except one, or the answer depends on how many numbers have a 1 in each bit position.
Per-Bit Counting
Python
1def single_number_ii(nums: list[int]) -> int:
2 """Modulo-3 Bitwise Finite State Machine: single element among triplets.
3 Time: O(N) | Space: O(1)
4 """
5 ones = 0 # bits whose count so far is 1 mod 3
6 twos = 0 # bits whose count so far is 2 mod 3
7 
8 # 1. Advance Each Bit Through the 0 -> 1 -> 2 -> 0 Cycle:
9 # ones picks up a bit on its first occurrence and keeps it until a second
10 # occurrence moves it to twos; twos must be computed from the updated ones,
11 # since twos only receives a bit that ones just released.
12 for x in nums:
13 ones = (ones ^ x) & ~twos
14 twos = (twos ^ x) & ~ones
15 
16 return ones
17 
18def single_number_ii_per_bit(nums: list[int]) -> int:
19 """Single Number II, one bit position at a time: the plain per-bit count.
20 Time: O(32 * N) | Space: O(1)
21 """
22 res = 0 # the single value, rebuilt one bit at a time
23 
24 # 1. Count Each Bit Position Across Every Number:
25 # A value that appears three times adds a multiple of 3 to each of its
26 # bit's counts, so the count modulo 3 is exactly the single value's bit.
27 for bit in range(32):
28 count = sum((x >> bit) & 1 for x in nums) # How many numbers have this bit set
29 if count % 3:
30 res |= 1 << bit
31 
32 # 2. Fix the Sign:
33 # res is built from 32 bits as an unsigned value; Python ints have no
34 # fixed width, so a set bit 31 must be converted back to a negative number by hand.
35 if res >= 2**31:
36 res -= 2**32
37 return res
Invariant: For every bit position, the bit is set in ones when its count so far is 1 modulo 3, in twos when it is 2, and in neither when it is 0.

Count each bit position on its own: at every position, the copies of a value that appears three times add a multiple of 3, so the count modulo 3 is exactly the single value's bit. ones and twos keep that count for all positions at once: a bit is set in ones when its count so far is 1 modulo 3 and in twos when it is 2, and ones = (ones ^ x) & ~twos followed by twos = (twos ^ x) & ~ones moves each bit of x one step through 0 → 1 → 2 → 0. The trap is the order: twos must be computed from the new ones, so swapping the two lines breaks the count.

See it run

Per-Bit Counting with ones and twos, step by step

x - · ones 00 · twos 00

x 10 · ones 10 · twos 00

x 10 · ones 10 · twos 00

x 10 · ones 00 · twos 00

x 10 · ones 00 · twos 10

x 11 · ones 01 · twos 10

x 11 · ones 01 · twos 00

x 10 · ones 11 · twos 00

x 10 · ones 11 · twos 00

x - · ones 11 · twos 00 · answer 3

Each column is one bit position. A bit set in ones means a count of 1; a bit set in twos means a count of 2.

  • x the bits of the number being added
  • read the register this line reads
  • write the register this line writes
  • answer the bits returned by the function

Start: ones = 00 and twos = 00. Every bit position has a count of 0.

x = 10. ones = (ones ^ x) & ~twos = (00 ^ 10) & ~00 = 10.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~10 = 00, using the new ones. Run first, with the old ones = 00, it would give twos = 10.

x = 10. ones = (ones ^ x) & ~twos = (10 ^ 10) & ~00 = 00.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~00 = 10, using the new ones.

x = 11. ones = (ones ^ x) & ~twos = (00 ^ 11) & ~10 = 01.

twos = (twos ^ x) & ~ones = (10 ^ 11) & ~01 = 00, using the new ones.

x = 10. ones = (ones ^ x) & ~twos = (01 ^ 10) & ~00 = 11.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~11 = 00, using the new ones.

Done: every bit that appears three times is back to a count of 0. The answer is ones = 11, which is 3.

x
bit 10
bit 00
ones
0
0
twos
0
0
1 / 10
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Updating twos before ones

    Mistake
    twos = (twos ^ x) & ~ones
    ones = (ones ^ x) & ~twos
    Fix
    ones = (ones ^ x) & ~twos
    twos = (twos ^ x) & ~ones

    What happens: twos must be computed from the new ones. The first copy of a bit moves it into ones, and ~ones then keeps it out of twos. With the lines swapped, twos reads the old ones. The first copy then lands in twos, and the count 0 → 1 → 2 → 0 is broken.

    Example: nums = [2, 2, 3, 2]
    Mistake: returns 0Fix: returns 3
  2. 2

    Gotcha 2: Testing count == 1 instead of count % 3

    Mistake
    if count == 1:
    Fix
    if count % 3:

    What happens: Each value that appears three times adds 3 to the count of each of its bits. So the single value's bit leaves a count of the form 3k + 1, not always 1. In [2, 2, 3, 2], bit 1 is set in all four numbers. Its count is 4, and == 1 misses it.

    Example: nums = [2, 2, 3, 2]
    Mistake: returns 1Fix: returns 3
  3. 3

    Gotcha 3: Returning res without the sign fix

    Mistake
    return res
    Fix
    if res >= 2**31:
        res -= 2**32
    return res

    What happens: The per-bit loop builds res from 32 bits, as an unsigned value. Python ints have no fixed width, so bit 31 does not make res negative. A negative answer such as -4 comes back as a large positive number. Subtract 2**32 when res >= 2**31.

    Example: nums = [-2, -2, -2, -4]
    Mistake: returns 4294967292Fix: returns -4
Not this one if…
  • Every other value appears exactly twice, as in Single Number (LC 136), so an even count is all there is to cancel. See XOR Cancel

Deep Dive

Why the count modulo 3 is the single value's bit

Look at one bit position, for example bit 1. Every value that appears three times has the same bit there in all three copies. So it adds 0 or 3 to the count of that position. The single value adds 0 or 1.

The total count at one position is therefore 3k plus the single value's bit. The remainder of the count divided by 3 is exactly that bit.

Example: in [2, 2, 3, 2], bit 1 is set in all four numbers, so its count is 4. The remainder 4 % 3 is 1, and the single value 3 has bit 1 set. Bit 0 is set only in 3, so its count is 1, and the remainder is 1. Bit 2 has count 0. The result is binary 11, which is 3.

This is the idea of single_number_ii_per_bit: the 32 positions never interact, so each one is solved on its own.

The state machine in ones and twos

The per-bit loop reads the whole array 32 times. ones and twos do the same work in one pass. Together they store, for every position, a count from 0 to 2 in two bits: (twos, ones) is (0, 0) for count 0, (0, 1) for count 1, and (1, 0) for count 2.

When a position receives a 1 in x, the count must move 0 to 1, then 1 to 2, then 2 back to 0. The line ones = (ones ^ x) & ~twos flips the ones bit and keeps it off when twos is set. The line twos = (twos ^ x) & ~ones does the same for twos, using the new ones.

Trace for [2, 2, 3, 2] after each number, in binary: after the first 2, ones = 10, twos = 0. After the second 2, ones = 0, twos = 10. After 3, ones = 1, twos = 0. After the last 2, ones = 11, twos = 0. The function returns ones, which is 3.

A position whose count is a multiple of 3 ends at (0, 0). Only the single value's bits remain in ones.

Why the order of the two lines matters

In the first line, ~twos is the old twos. In the second line, ~ones must be the new ones. This order is what makes the three states a cycle.

Take a position whose count is 0 and receives a 1. The first line sets ones. The second line sees ~ones as off for this position, so twos stays off. The state is (0, 1), which is count 1.

If you write the twos line first, it reads the old ones, which is still off. It sets twos, and then the ones line is blocked by ~twos. The first copy lands in twos and the cycle breaks. With [2, 2, 3, 2] the swapped code returns 0 instead of 3.

Cost, the sign, and other counts

single_number_ii makes one pass and uses two integers: O(N) time and O(1) space. single_number_ii_per_bit makes 32 passes: O(32 * N) time and O(1) space. Both are linear in N.

Python integers have no fixed width. The ones/twos version works for negative numbers as written, because the bit operations follow the same rules on every position. The per-bit version builds res from 32 positions, so it must subtract 2**32 when res >= 2**31. For [-2, -2, -2, -4] the function then returns -4 and not 4294967292.

For a different repeat count k, the per-bit idea stays the same: test count % k. Only the shortcut changes, because ones and twos store counts up to 2 and a larger k needs more count bits. Use the per-bit loop when k is not 3.

The same per-bit view solves Total Hamming Distance (LC 477). For each position, ones_count numbers have a 1 and n - ones_count have a 0, so the position adds ones_count * (n - ones_count) to the answer. For [4, 14, 2] the total is 6.

60-Second Pitch

"XOR cancels pairs, but here every other value appears three times, so I need a different counter. I look at one bit position at a time. Triplets add a multiple of 3 to each position, so the count modulo 3 is exactly the single value's bit. The simple version loops over 32 positions, counts the 1 bits with sum((x >> bit) & 1 for x in nums), and sets the bit when count % 3 is not 0. It takes O(32 * N) time and O(1) space. I fix the sign at the end. To finish in one pass, I keep the count of every position in two integers, ones and twos, and update them in this order: ones first, then twos from the new ones. The time is O(N) and the space is O(1)."

Common Questions

Why does XOR not solve Single Number II (LC 137)?

XOR cancels a value only when it appears an even number of times. A value that appears three times leaves one copy in the result. So the answer of XOR is mixed with every triplet. A counter modulo 3 per bit position removes the triplets completely.

What are ones and twos storing?

For each bit position, they store the count of 1s seen so far, modulo 3. A position set in ones has count 1. A position set in twos has count 2. A position set in neither has count 0. The two integers hold all 32 counters in parallel.

How would you change the code if every other value appeared 5 times?

Use the per-bit loop and test count % 5. It needs no change except the modulus. The two-integer shortcut needs more registers, because counts go up to 4 and need 3 bits per position. For an interview, the per-bit loop is the safer answer.

What are the time and space complexity?

single_number_ii is O(N) time and O(1) space. single_number_ii_per_bit is O(32 * N) time and O(1) space. Because 32 is a constant, both are linear in N.

How does the same idea solve Total Hamming Distance (LC 477)?

Count per position again. If c of the n numbers have a 1 at a position, then c * (n - c) pairs differ there. Add this over the 32 positions. That is O(32 * N) time instead of comparing all O(N^2) pairs.

SWE Reasoning

Spot it

  • Every value appears k times, with k of 3 or more, except one value that appears a different number of times. XOR alone cannot cancel an odd count, so Single Number (LC 136) logic fails.
  • The question asks about the number of values that have a 1 in a given bit position, or a total over all pairs of numbers (Total Hamming Distance (LC 477)).
  • The constraints ask for O(1) extra space, which rules out a hash map of counts.
  • The numbers are 32-bit integers, so there are only 32 positions to examine.

The invariant, step by step

  1. Treat each of the 32 bit positions as its own counter. A position never affects another position.
  2. Copies of a repeated value add 0 or 3 to a position, so the count modulo 3 at each position equals the single value's bit.
  3. ones and twos store that count modulo 3 for all positions at once: a position is in ones for count 1, in twos for count 2, and in neither for count 0.
  4. For each x, ones = (ones ^ x) & ~twos moves a position from count 0 to 1 and from 1 to 2 out of ones. Then twos = (twos ^ x) & ~ones moves it from 1 to 2 and from 2 to 0 out of twos.
  5. After all numbers, every position that belongs to a triplet is back at count 0. Only the single value's positions are in ones.
  6. single_number_ii returns ones.

Traps

  • Lines in the wrong order. If twos is computed before ones, it reads the old ones. The first copy lands in twos. [2, 2, 3, 2] returns 0 instead of 3.
  • Testing count == 1. The single value's bit leaves a count of 3k + 1, so a count of 4 is missed. Use count % 3.
  • No sign fix in the per-bit version. res is built as an unsigned 32-bit value. [-2, -2, -2, -4] returns 4294967292 instead of -4 until you subtract 2**32 when res >= 2**31.
  • Using XOR alone. XOR cancels pairs. Three copies leave one copy, so the result is the XOR of the single value and one copy of every other value.
  • Assuming k = 3 in the shortcut. The two-register shortcut is written for counts modulo 3. For another k, use the per-bit loop with count % k.

Practice

Canonical LeetCode:Single Number II (LC 137)Total Hamming Distance (LC 477)Minimum Flips to Make a OR b Equal to c (LC 1318)Largest Combination With Bitwise AND Greater Than Zero (LC 2275)
Theory Context•Bit Manipulation

Builds on XOR Cancel, which you haven’t finished yet.

P3MediumBuilt on XOR Cancel~3 min speedrun

Per-Bit Counting (Single Number II / Bitwise State Machine)

Built on
XOR CancelA count modulo 3 is kept for each bit, where XOR Cancel keeps one parity bit.

Single Number II (LC 137)(opens leetcode.com)

An integer array nums has every value appearing exactly three times, except for a single value that appears only once. Return that unique value.

Your solution must run in linear time and use only constant extra space.

Example 1
Input:nums = [2,2,3,2]
Output:3
2 appears three times; 3 appears once.

Per-Bit Counting

value stream âž” bit registers (ones, twos, ...) âž” survivor
Spot it when: Every value appears k times (k of 3 or more) except one, or the answer depends on how many numbers have a 1 in each bit position.
Per-Bit Counting
Python
1def single_number_ii(nums: list[int]) -> int:
2 """Modulo-3 Bitwise Finite State Machine: single element among triplets.
3 Time: O(N) | Space: O(1)
4 """
5 ones = 0 # bits whose count so far is 1 mod 3
6 twos = 0 # bits whose count so far is 2 mod 3
7 
8 # 1. Advance Each Bit Through the 0 -> 1 -> 2 -> 0 Cycle:
9 # ones picks up a bit on its first occurrence and keeps it until a second
10 # occurrence moves it to twos; twos must be computed from the updated ones,
11 # since twos only receives a bit that ones just released.
12 for x in nums:
13 ones = (ones ^ x) & ~twos
14 twos = (twos ^ x) & ~ones
15 
16 return ones
17 
18def single_number_ii_per_bit(nums: list[int]) -> int:
19 """Single Number II, one bit position at a time: the plain per-bit count.
20 Time: O(32 * N) | Space: O(1)
21 """
22 res = 0 # the single value, rebuilt one bit at a time
23 
24 # 1. Count Each Bit Position Across Every Number:
25 # A value that appears three times adds a multiple of 3 to each of its
26 # bit's counts, so the count modulo 3 is exactly the single value's bit.
27 for bit in range(32):
28 count = sum((x >> bit) & 1 for x in nums) # How many numbers have this bit set
29 if count % 3:
30 res |= 1 << bit
31 
32 # 2. Fix the Sign:
33 # res is built from 32 bits as an unsigned value; Python ints have no
34 # fixed width, so a set bit 31 must be converted back to a negative number by hand.
35 if res >= 2**31:
36 res -= 2**32
37 return res
Invariant: For every bit position, the bit is set in ones when its count so far is 1 modulo 3, in twos when it is 2, and in neither when it is 0.

Count each bit position on its own: at every position, the copies of a value that appears three times add a multiple of 3, so the count modulo 3 is exactly the single value's bit. ones and twos keep that count for all positions at once: a bit is set in ones when its count so far is 1 modulo 3 and in twos when it is 2, and ones = (ones ^ x) & ~twos followed by twos = (twos ^ x) & ~ones moves each bit of x one step through 0 → 1 → 2 → 0. The trap is the order: twos must be computed from the new ones, so swapping the two lines breaks the count.

See it run

Per-Bit Counting with ones and twos, step by step

x - · ones 00 · twos 00

x 10 · ones 10 · twos 00

x 10 · ones 10 · twos 00

x 10 · ones 00 · twos 00

x 10 · ones 00 · twos 10

x 11 · ones 01 · twos 10

x 11 · ones 01 · twos 00

x 10 · ones 11 · twos 00

x 10 · ones 11 · twos 00

x - · ones 11 · twos 00 · answer 3

Each column is one bit position. A bit set in ones means a count of 1; a bit set in twos means a count of 2.

  • x the bits of the number being added
  • read the register this line reads
  • write the register this line writes
  • answer the bits returned by the function

Start: ones = 00 and twos = 00. Every bit position has a count of 0.

x = 10. ones = (ones ^ x) & ~twos = (00 ^ 10) & ~00 = 10.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~10 = 00, using the new ones. Run first, with the old ones = 00, it would give twos = 10.

x = 10. ones = (ones ^ x) & ~twos = (10 ^ 10) & ~00 = 00.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~00 = 10, using the new ones.

x = 11. ones = (ones ^ x) & ~twos = (00 ^ 11) & ~10 = 01.

twos = (twos ^ x) & ~ones = (10 ^ 11) & ~01 = 00, using the new ones.

x = 10. ones = (ones ^ x) & ~twos = (01 ^ 10) & ~00 = 11.

twos = (twos ^ x) & ~ones = (00 ^ 10) & ~11 = 00, using the new ones.

Done: every bit that appears three times is back to a count of 0. The answer is ones = 11, which is 3.

x
bit 10
bit 00
ones
0
0
twos
0
0
1 / 10
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Updating twos before ones

    Mistake
    twos = (twos ^ x) & ~ones
    ones = (ones ^ x) & ~twos
    Fix
    ones = (ones ^ x) & ~twos
    twos = (twos ^ x) & ~ones

    What happens: twos must be computed from the new ones. The first copy of a bit moves it into ones, and ~ones then keeps it out of twos. With the lines swapped, twos reads the old ones. The first copy then lands in twos, and the count 0 → 1 → 2 → 0 is broken.

    Example: nums = [2, 2, 3, 2]
    Mistake: returns 0Fix: returns 3
  2. 2

    Gotcha 2: Testing count == 1 instead of count % 3

    Mistake
    if count == 1:
    Fix
    if count % 3:

    What happens: Each value that appears three times adds 3 to the count of each of its bits. So the single value's bit leaves a count of the form 3k + 1, not always 1. In [2, 2, 3, 2], bit 1 is set in all four numbers. Its count is 4, and == 1 misses it.

    Example: nums = [2, 2, 3, 2]
    Mistake: returns 1Fix: returns 3
  3. 3

    Gotcha 3: Returning res without the sign fix

    Mistake
    return res
    Fix
    if res >= 2**31:
        res -= 2**32
    return res

    What happens: The per-bit loop builds res from 32 bits, as an unsigned value. Python ints have no fixed width, so bit 31 does not make res negative. A negative answer such as -4 comes back as a large positive number. Subtract 2**32 when res >= 2**31.

    Example: nums = [-2, -2, -2, -4]
    Mistake: returns 4294967292Fix: returns -4
Not this one if…
  • Every other value appears exactly twice, as in Single Number (LC 136), so an even count is all there is to cancel. See XOR Cancel

Deep Dive

Why the count modulo 3 is the single value's bit

Look at one bit position, for example bit 1. Every value that appears three times has the same bit there in all three copies. So it adds 0 or 3 to the count of that position. The single value adds 0 or 1.

The total count at one position is therefore 3k plus the single value's bit. The remainder of the count divided by 3 is exactly that bit.

Example: in [2, 2, 3, 2], bit 1 is set in all four numbers, so its count is 4. The remainder 4 % 3 is 1, and the single value 3 has bit 1 set. Bit 0 is set only in 3, so its count is 1, and the remainder is 1. Bit 2 has count 0. The result is binary 11, which is 3.

This is the idea of single_number_ii_per_bit: the 32 positions never interact, so each one is solved on its own.

The state machine in ones and twos

The per-bit loop reads the whole array 32 times. ones and twos do the same work in one pass. Together they store, for every position, a count from 0 to 2 in two bits: (twos, ones) is (0, 0) for count 0, (0, 1) for count 1, and (1, 0) for count 2.

When a position receives a 1 in x, the count must move 0 to 1, then 1 to 2, then 2 back to 0. The line ones = (ones ^ x) & ~twos flips the ones bit and keeps it off when twos is set. The line twos = (twos ^ x) & ~ones does the same for twos, using the new ones.

Trace for [2, 2, 3, 2] after each number, in binary: after the first 2, ones = 10, twos = 0. After the second 2, ones = 0, twos = 10. After 3, ones = 1, twos = 0. After the last 2, ones = 11, twos = 0. The function returns ones, which is 3.

A position whose count is a multiple of 3 ends at (0, 0). Only the single value's bits remain in ones.

Why the order of the two lines matters

In the first line, ~twos is the old twos. In the second line, ~ones must be the new ones. This order is what makes the three states a cycle.

Take a position whose count is 0 and receives a 1. The first line sets ones. The second line sees ~ones as off for this position, so twos stays off. The state is (0, 1), which is count 1.

If you write the twos line first, it reads the old ones, which is still off. It sets twos, and then the ones line is blocked by ~twos. The first copy lands in twos and the cycle breaks. With [2, 2, 3, 2] the swapped code returns 0 instead of 3.

Cost, the sign, and other counts

single_number_ii makes one pass and uses two integers: O(N) time and O(1) space. single_number_ii_per_bit makes 32 passes: O(32 * N) time and O(1) space. Both are linear in N.

Python integers have no fixed width. The ones/twos version works for negative numbers as written, because the bit operations follow the same rules on every position. The per-bit version builds res from 32 positions, so it must subtract 2**32 when res >= 2**31. For [-2, -2, -2, -4] the function then returns -4 and not 4294967292.

For a different repeat count k, the per-bit idea stays the same: test count % k. Only the shortcut changes, because ones and twos store counts up to 2 and a larger k needs more count bits. Use the per-bit loop when k is not 3.

The same per-bit view solves Total Hamming Distance (LC 477). For each position, ones_count numbers have a 1 and n - ones_count have a 0, so the position adds ones_count * (n - ones_count) to the answer. For [4, 14, 2] the total is 6.

60-Second Pitch

"XOR cancels pairs, but here every other value appears three times, so I need a different counter. I look at one bit position at a time. Triplets add a multiple of 3 to each position, so the count modulo 3 is exactly the single value's bit. The simple version loops over 32 positions, counts the 1 bits with sum((x >> bit) & 1 for x in nums), and sets the bit when count % 3 is not 0. It takes O(32 * N) time and O(1) space. I fix the sign at the end. To finish in one pass, I keep the count of every position in two integers, ones and twos, and update them in this order: ones first, then twos from the new ones. The time is O(N) and the space is O(1)."

Common Questions

Why does XOR not solve Single Number II (LC 137)?

XOR cancels a value only when it appears an even number of times. A value that appears three times leaves one copy in the result. So the answer of XOR is mixed with every triplet. A counter modulo 3 per bit position removes the triplets completely.

What are ones and twos storing?

For each bit position, they store the count of 1s seen so far, modulo 3. A position set in ones has count 1. A position set in twos has count 2. A position set in neither has count 0. The two integers hold all 32 counters in parallel.

How would you change the code if every other value appeared 5 times?

Use the per-bit loop and test count % 5. It needs no change except the modulus. The two-integer shortcut needs more registers, because counts go up to 4 and need 3 bits per position. For an interview, the per-bit loop is the safer answer.

What are the time and space complexity?

single_number_ii is O(N) time and O(1) space. single_number_ii_per_bit is O(32 * N) time and O(1) space. Because 32 is a constant, both are linear in N.

How does the same idea solve Total Hamming Distance (LC 477)?

Count per position again. If c of the n numbers have a 1 at a position, then c * (n - c) pairs differ there. Add this over the 32 positions. That is O(32 * N) time instead of comparing all O(N^2) pairs.

SWE Reasoning

Spot it

  • Every value appears k times, with k of 3 or more, except one value that appears a different number of times. XOR alone cannot cancel an odd count, so Single Number (LC 136) logic fails.
  • The question asks about the number of values that have a 1 in a given bit position, or a total over all pairs of numbers (Total Hamming Distance (LC 477)).
  • The constraints ask for O(1) extra space, which rules out a hash map of counts.
  • The numbers are 32-bit integers, so there are only 32 positions to examine.

The invariant, step by step

  1. Treat each of the 32 bit positions as its own counter. A position never affects another position.
  2. Copies of a repeated value add 0 or 3 to a position, so the count modulo 3 at each position equals the single value's bit.
  3. ones and twos store that count modulo 3 for all positions at once: a position is in ones for count 1, in twos for count 2, and in neither for count 0.
  4. For each x, ones = (ones ^ x) & ~twos moves a position from count 0 to 1 and from 1 to 2 out of ones. Then twos = (twos ^ x) & ~ones moves it from 1 to 2 and from 2 to 0 out of twos.
  5. After all numbers, every position that belongs to a triplet is back at count 0. Only the single value's positions are in ones.
  6. single_number_ii returns ones.

Traps

  • Lines in the wrong order. If twos is computed before ones, it reads the old ones. The first copy lands in twos. [2, 2, 3, 2] returns 0 instead of 3.
  • Testing count == 1. The single value's bit leaves a count of 3k + 1, so a count of 4 is missed. Use count % 3.
  • No sign fix in the per-bit version. res is built as an unsigned 32-bit value. [-2, -2, -2, -4] returns 4294967292 instead of -4 until you subtract 2**32 when res >= 2**31.
  • Using XOR alone. XOR cancels pairs. Three copies leave one copy, so the result is the XOR of the single value and one copy of every other value.
  • Assuming k = 3 in the shortcut. The two-register shortcut is written for counts modulo 3. For another k, use the per-bit loop with count % k.

Practice

Canonical LeetCode:Single Number II (LC 137)Total Hamming Distance (LC 477)Minimum Flips to Make a OR b Equal to c (LC 1318)Largest Combination With Bitwise AND Greater Than Zero (LC 2275)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•