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 Bit Tricks, which you haven’t finished yet.

P2MediumBuilt on Bit Tricks~3 min speedrun

Shared Binary Prefix (Bitwise AND of Numbers Range)

Built on
Bit TricksShift two numbers right together until they are equal, count the shifts in shift, then shift the equal value back left by shift.
The problem

Bitwise AND of Numbers Range (LC 201)(opens leetcode.com)

You get two integers, left and right, with left <= right. Take every integer from left up to right, including both ends. Combine all of them with the bitwise AND operator. Bitwise AND compares numbers bit by bit and keeps a bit only when every number has a 1 in that place.

Return that single result.

Example 1
Input:left = 5, right = 7
Output:4
The numbers are 5 (101), 6 (110) and 7 (111). The top bit is 1 in all three, and each of the two lower bits is 0 in at least one of them. So the AND is 100, which is 4.

Shared Prefix

left, right ➔ shift both right until equal, counting shift ➔ shared prefix << shift
Spot it when: You must combine every integer between two bounds with AND, or find the leading bits that two numbers share.
Shared Prefix
Python
1def range_bitwise_and(left: int, right: int) -> int:
2 """Bitwise AND of Numbers Range: the shared binary prefix of the two ends, followed by zeros.
3 Time: O(log right) | Space: O(1)
4 """
5 # shift: how many low bits have been removed from both ends so far
6 shift = 0
7 
8 # 1. Shift Both Ends Right Until They Are Equal:
9 # Every bit below the highest place where the ends differ is 0 in some number of the range, so it cannot survive the AND.
10 # Removing the lowest bit of both ends together keeps their shared prefix and counts how many bits were removed.
11 while left != right:
12 left >>= 1
13 right >>= 1
14 shift += 1
15 
16 # 2. Shift The Shared Prefix Back:
17 # The equal value is the prefix. Shifting it left by shift puts it in its original place with zeros below.
18 return left << shift
Invariant: left and right are the original ends with their lowest shift bits removed, and their shared prefix is the shared prefix of the original ends.

Only the binary prefix that left and right share can survive the AND, so shift both right until they are equal and count the shifts in shift. Counting up from left to right passes the number prefix followed by 0111...1 and then the next number, prefix followed by 1000...0. These two numbers have no 1 bit in common below the prefix, so every lower bit is cleared, while every number in the range keeps the prefix. After the loop, left holds only the prefix, so return left << shift, not left: for left = 5 and right = 7 the loop ends with left = 1 and shift = 2, and 1 is wrong where 1 << 2 = 4 is right.

See it run

Bitwise AND of Numbers Range, step by step

left 22 · right 30 · shift 0

left 22 · right 30 · shift 0

left 11 · right 15 · shift 1

left 11 · right 15 · shift 1

left 5 · right 7 · shift 2

left 5 · right 7 · shift 2

left 2 · right 3 · shift 3

left 2 · right 3 · shift 3

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4 · answer 16

The top row is left, the middle row is right and the bottom row is the returned value. Each column is one bit position, with the highest position on the left.

  • drop the lowest bit that the next round removes
  • equal the shared prefix, once left and right are the same
  • written the returned value, left << shift

Start: left = 22 is 00010110 and right = 30 is 00011110. shift = 0.

22 != 30, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 11 and right = 15. shift = 1.

11 != 15, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 5 and right = 7. shift = 2.

5 != 7, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 2 and right = 3. shift = 3.

2 != 3, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 1 and right = 1. shift = 4.

left = right = 1, so the loop ends. This value is the shared prefix.

return left would give 1, which is the prefix without its 4 zeros below. The answer is larger.

left << shift is 1 * 16 = 16. The prefix is back in its original place.

Done: the AND of every number from 22 to 30 is 16.

left
70
60
50
41
30
21
11
00
right
0
0
0
1
1
1
1
0
result
0
0
0
0
0
0
0
0
1 / 13
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Returning left without shifting it back

    Mistake
    return left
    Fix
    return left << shift

    What happens: After the loop, left and right hold only the shared prefix, with shift low bits removed. return left gives that short number. The answer needs the same prefix in its original place, with shift zeros below it, so the right answer is 2 ** shift times larger.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: returns 1Fix: returns 4
  2. 2

    Gotcha 2: Returning left & right of the two ends

    Mistake
    return left & right
    Fix
    return left << shift

    What happens: left & right only looks at the two ends. A number between them can have a 0 in a place where both ends have a 1, and then the AND of the whole range clears that bit. For 5 (101) and 7 (111), the number 6 (110) clears bit 0, which both ends have set.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: returns 5Fix: returns 4
  3. 3

    Gotcha 3: Shifting only right in the loop

    Mistake
    right >>= 1
    Fix
    left >>= 1
    right >>= 1

    What happens: The loop stops when left equals right. If only right is shifted, it falls toward 0 while left stays the same. When left is larger than 0, right never becomes equal to it, so the loop never ends.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: the loop never endsFix: returns 4
  4. 4

    Gotcha 4: Looping over every number of the range with a running AND

    What happens: for value in range(left, right + 1): result &= value gives the right answer, but the range can hold about 2 billion numbers. The shift loop runs at most 31 times, because each round removes one bit from both ends.

Not this one if…
  • The result is built from both numbers bit by bit, such as the sum with carries in Sum of Two Integers (LC 371), not only from the leading bits that they share. See Carry Add
  • The input is one number whose 1 bits you count or clear, as in Number of 1 Bits (LC 191), not the two ends of a range. See Kernighan's Bit Trick

Deep Dive

Why only the shared prefix survives the AND

Bit Tricks already taught the shift and the mask. This card adds one idea: the AND of a whole range is the binary prefix that left and right share, followed by zeros.

Take left = 22 and right = 30. In 8 bits, 22 is 00010110 and 30 is 00011110. They agree on the bits at positions 7 to 4, and the highest position where they differ is position 3.

Counting up from 22 to 30 must pass a number with the shared prefix followed by 0111...1 and then the next number, the shared prefix followed by 1000...0. Here those two numbers are 23 (00010111) and 24 (00011000). They have no 1 bit in common below the prefix. So the AND of the range has a 0 in every position below the prefix.

Every number in the range keeps the prefix, because counting up from 22 to 30 never changes the bits above position 3. The AND of the range of 22 to 30 is therefore 00010000, which is 16. I checked this against a loop that ANDs every number from 22 to 30, and the result is 16.

What the shift loop does, round by round

The loop while left != right removes the lowest bit of both numbers with left >>= 1 and right >>= 1. It adds 1 to shift each time.

For left = 22 and right = 30, the pairs are (22, 30), (11, 15), (5, 7), (2, 3) and (1, 1). That is 4 rounds, so shift = 4. The loop ends because left and right are both 1.

The final left is the shared prefix without its trailing zeros. To put it back in place, the function returns left << shift, which is 1 << 4 = 16.

The number of rounds equals the number of bits in left ^ right. For 22 ^ 30 = 8, that is 4 bits. The XOR of the two ends has its highest 1 bit exactly where they first differ. So the loop removes every bit from that position down.

The cost and the edge cases

Each round removes one bit from both numbers, so the loop runs at most as many times as the larger number has bits. For a 31-bit input, that is at most 31 rounds. The time is O(log right) and the space is O(1).

A loop over every number of the range gives the same answer, but the range can hold about 2 billion numbers. The shift loop does not depend on the length of the range.

Edge cases: when left == right, the loop does not run and the answer is left. For left = 0 and right = 0 the answer is 0. For left = 1 and right = 2147483647, the two ends share no prefix, the loop runs 31 times, and the answer is 0. For left = 7 and right = 8, which are 0111 and 1000, the answer is also 0.

There is a second way to get the same result: while right > left: right &= right - 1, then return right. Each step clears the lowest 1 bit of right, as in Kernighan's Bit Trick. I compared it with the shift loop on 50,000 random pairs, and the answers matched.

60-Second Pitch

"The AND of a range keeps only the leading bits that every number in the range shares. Below the first position where left and right differ, the range contains a number ending in 0111...1 and the next number ending in 1000...0. So every lower bit becomes 0. I find the shared prefix by shifting left and right right together until they are equal, and I count the shifts in shift. Then I return left << shift, so the prefix goes back to its original place. For 22 to 30, the loop runs 4 times, and the answer is 1 shifted left by 4, which is 16. The loop runs at most 31 times, so the time is O(log right) and the space is O(1)."

Common Questions

What is the time and space complexity?

O(log right) time and O(1) space. Each round removes one bit from both numbers, so there are at most 31 rounds for a 31-bit input. The length of the range does not matter.

Why is left & right of the two ends not enough?

A number between the ends can clear a bit that both ends have set. For left = 22 and right = 30, the ends give 22, but 23 and 24 have no 1 bit in common below the prefix, so the range gives 16.

What happens when left equals right?

The loop does not run. shift stays 0, and the function returns left << 0, which is left. That is correct, because the range holds one number.

Is there a version without a shift counter?

Yes. Use while right > left: right &= right - 1, then return right. Each step clears the lowest 1 bit of right. When right is no longer larger than left, the remaining 1 bits are the shared prefix. It gives the same answers as the shift loop.

How does this differ from Sum of Two Integers (LC 371)?

Here the answer uses only the leading bits that the two numbers share. In Sum of Two Integers (LC 371), the answer is built from both numbers bit by bit, with carries, so no bit can be ignored.

SWE Reasoning

Spot it

  • The statement asks for the bitwise AND of every integer between two bounds, inclusive.
  • The range can be as large as 2 billion numbers, so a loop over the range is too slow.
  • The statement asks for the common leading bits of two numbers, or the longest shared binary prefix.
  • A small example by hand shows that the answer is always prefix followed by zeros.

The invariant, step by step

  1. Start with shift = 0. left and right are the original ends.
  2. A round runs left >>= 1, right >>= 1 and shift += 1. Now left and right are the original ends with their lowest shift bits removed.
  3. Removing the same number of low bits from both ends keeps their shared prefix. It does not matter which low bits were removed.
  4. The loop stops when left == right. At that moment the value is exactly the shared prefix of the original ends.
  5. Every bit below the prefix is 0 in the AND, because the range contains the number prefix followed by 0111...1 and the number prefix followed by 1000...0.
  6. left << shift puts the prefix back in its original place with shift zeros below it. That is the answer.

Traps

  • return left without << shift. The result is the prefix without its trailing zeros. For left = 5 and right = 7, it returns 1 instead of 4. For left = 22 and right = 30, it returns 1 instead of 16.
  • return left & right of the two ends. A number inside the range can have a 0 where both ends have a 1. For left = 22 and right = 30, this returns 22, but the right answer is 16.
  • Shifting only right. left never changes, so for left > 0 the two values may never become equal. The loop does not end.
  • Looping over the whole range with result &= value. The answer is right, but the range can hold about 2 billion numbers, so the solution is too slow.

Practice

Canonical LeetCode:Bitwise AND of Numbers Range (LC 201)
Theory Context•Bit Manipulation

Builds on Bit Tricks, which you haven’t finished yet.

P2MediumBuilt on Bit Tricks~3 min speedrun

Shared Binary Prefix (Bitwise AND of Numbers Range)

Built on
Bit TricksShift two numbers right together until they are equal, count the shifts in shift, then shift the equal value back left by shift.
The problem

Bitwise AND of Numbers Range (LC 201)(opens leetcode.com)

You get two integers, left and right, with left <= right. Take every integer from left up to right, including both ends. Combine all of them with the bitwise AND operator. Bitwise AND compares numbers bit by bit and keeps a bit only when every number has a 1 in that place.

Return that single result.

Example 1
Input:left = 5, right = 7
Output:4
The numbers are 5 (101), 6 (110) and 7 (111). The top bit is 1 in all three, and each of the two lower bits is 0 in at least one of them. So the AND is 100, which is 4.

Shared Prefix

left, right ➔ shift both right until equal, counting shift ➔ shared prefix << shift
Spot it when: You must combine every integer between two bounds with AND, or find the leading bits that two numbers share.
Shared Prefix
Python
1def range_bitwise_and(left: int, right: int) -> int:
2 """Bitwise AND of Numbers Range: the shared binary prefix of the two ends, followed by zeros.
3 Time: O(log right) | Space: O(1)
4 """
5 # shift: how many low bits have been removed from both ends so far
6 shift = 0
7 
8 # 1. Shift Both Ends Right Until They Are Equal:
9 # Every bit below the highest place where the ends differ is 0 in some number of the range, so it cannot survive the AND.
10 # Removing the lowest bit of both ends together keeps their shared prefix and counts how many bits were removed.
11 while left != right:
12 left >>= 1
13 right >>= 1
14 shift += 1
15 
16 # 2. Shift The Shared Prefix Back:
17 # The equal value is the prefix. Shifting it left by shift puts it in its original place with zeros below.
18 return left << shift
Invariant: left and right are the original ends with their lowest shift bits removed, and their shared prefix is the shared prefix of the original ends.

Only the binary prefix that left and right share can survive the AND, so shift both right until they are equal and count the shifts in shift. Counting up from left to right passes the number prefix followed by 0111...1 and then the next number, prefix followed by 1000...0. These two numbers have no 1 bit in common below the prefix, so every lower bit is cleared, while every number in the range keeps the prefix. After the loop, left holds only the prefix, so return left << shift, not left: for left = 5 and right = 7 the loop ends with left = 1 and shift = 2, and 1 is wrong where 1 << 2 = 4 is right.

See it run

Bitwise AND of Numbers Range, step by step

left 22 · right 30 · shift 0

left 22 · right 30 · shift 0

left 11 · right 15 · shift 1

left 11 · right 15 · shift 1

left 5 · right 7 · shift 2

left 5 · right 7 · shift 2

left 2 · right 3 · shift 3

left 2 · right 3 · shift 3

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4

left 1 · right 1 · shift 4 · answer 16

The top row is left, the middle row is right and the bottom row is the returned value. Each column is one bit position, with the highest position on the left.

  • drop the lowest bit that the next round removes
  • equal the shared prefix, once left and right are the same
  • written the returned value, left << shift

Start: left = 22 is 00010110 and right = 30 is 00011110. shift = 0.

22 != 30, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 11 and right = 15. shift = 1.

11 != 15, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 5 and right = 7. shift = 2.

5 != 7, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 2 and right = 3. shift = 3.

2 != 3, so the loop runs. Both lowest bits are about to be removed.

left >>= 1 and right >>= 1 give left = 1 and right = 1. shift = 4.

left = right = 1, so the loop ends. This value is the shared prefix.

return left would give 1, which is the prefix without its 4 zeros below. The answer is larger.

left << shift is 1 * 16 = 16. The prefix is back in its original place.

Done: the AND of every number from 22 to 30 is 16.

left
70
60
50
41
30
21
11
00
right
0
0
0
1
1
1
1
0
result
0
0
0
0
0
0
0
0
1 / 13
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Returning left without shifting it back

    Mistake
    return left
    Fix
    return left << shift

    What happens: After the loop, left and right hold only the shared prefix, with shift low bits removed. return left gives that short number. The answer needs the same prefix in its original place, with shift zeros below it, so the right answer is 2 ** shift times larger.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: returns 1Fix: returns 4
  2. 2

    Gotcha 2: Returning left & right of the two ends

    Mistake
    return left & right
    Fix
    return left << shift

    What happens: left & right only looks at the two ends. A number between them can have a 0 in a place where both ends have a 1, and then the AND of the whole range clears that bit. For 5 (101) and 7 (111), the number 6 (110) clears bit 0, which both ends have set.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: returns 5Fix: returns 4
  3. 3

    Gotcha 3: Shifting only right in the loop

    Mistake
    right >>= 1
    Fix
    left >>= 1
    right >>= 1

    What happens: The loop stops when left equals right. If only right is shifted, it falls toward 0 while left stays the same. When left is larger than 0, right never becomes equal to it, so the loop never ends.

    Example: Bitwise AND of Numbers Range (LC 201): left = 5, right = 7
    Mistake: the loop never endsFix: returns 4
  4. 4

    Gotcha 4: Looping over every number of the range with a running AND

    What happens: for value in range(left, right + 1): result &= value gives the right answer, but the range can hold about 2 billion numbers. The shift loop runs at most 31 times, because each round removes one bit from both ends.

Not this one if…
  • The result is built from both numbers bit by bit, such as the sum with carries in Sum of Two Integers (LC 371), not only from the leading bits that they share. See Carry Add
  • The input is one number whose 1 bits you count or clear, as in Number of 1 Bits (LC 191), not the two ends of a range. See Kernighan's Bit Trick

Deep Dive

Why only the shared prefix survives the AND

Bit Tricks already taught the shift and the mask. This card adds one idea: the AND of a whole range is the binary prefix that left and right share, followed by zeros.

Take left = 22 and right = 30. In 8 bits, 22 is 00010110 and 30 is 00011110. They agree on the bits at positions 7 to 4, and the highest position where they differ is position 3.

Counting up from 22 to 30 must pass a number with the shared prefix followed by 0111...1 and then the next number, the shared prefix followed by 1000...0. Here those two numbers are 23 (00010111) and 24 (00011000). They have no 1 bit in common below the prefix. So the AND of the range has a 0 in every position below the prefix.

Every number in the range keeps the prefix, because counting up from 22 to 30 never changes the bits above position 3. The AND of the range of 22 to 30 is therefore 00010000, which is 16. I checked this against a loop that ANDs every number from 22 to 30, and the result is 16.

What the shift loop does, round by round

The loop while left != right removes the lowest bit of both numbers with left >>= 1 and right >>= 1. It adds 1 to shift each time.

For left = 22 and right = 30, the pairs are (22, 30), (11, 15), (5, 7), (2, 3) and (1, 1). That is 4 rounds, so shift = 4. The loop ends because left and right are both 1.

The final left is the shared prefix without its trailing zeros. To put it back in place, the function returns left << shift, which is 1 << 4 = 16.

The number of rounds equals the number of bits in left ^ right. For 22 ^ 30 = 8, that is 4 bits. The XOR of the two ends has its highest 1 bit exactly where they first differ. So the loop removes every bit from that position down.

The cost and the edge cases

Each round removes one bit from both numbers, so the loop runs at most as many times as the larger number has bits. For a 31-bit input, that is at most 31 rounds. The time is O(log right) and the space is O(1).

A loop over every number of the range gives the same answer, but the range can hold about 2 billion numbers. The shift loop does not depend on the length of the range.

Edge cases: when left == right, the loop does not run and the answer is left. For left = 0 and right = 0 the answer is 0. For left = 1 and right = 2147483647, the two ends share no prefix, the loop runs 31 times, and the answer is 0. For left = 7 and right = 8, which are 0111 and 1000, the answer is also 0.

There is a second way to get the same result: while right > left: right &= right - 1, then return right. Each step clears the lowest 1 bit of right, as in Kernighan's Bit Trick. I compared it with the shift loop on 50,000 random pairs, and the answers matched.

60-Second Pitch

"The AND of a range keeps only the leading bits that every number in the range shares. Below the first position where left and right differ, the range contains a number ending in 0111...1 and the next number ending in 1000...0. So every lower bit becomes 0. I find the shared prefix by shifting left and right right together until they are equal, and I count the shifts in shift. Then I return left << shift, so the prefix goes back to its original place. For 22 to 30, the loop runs 4 times, and the answer is 1 shifted left by 4, which is 16. The loop runs at most 31 times, so the time is O(log right) and the space is O(1)."

Common Questions

What is the time and space complexity?

O(log right) time and O(1) space. Each round removes one bit from both numbers, so there are at most 31 rounds for a 31-bit input. The length of the range does not matter.

Why is left & right of the two ends not enough?

A number between the ends can clear a bit that both ends have set. For left = 22 and right = 30, the ends give 22, but 23 and 24 have no 1 bit in common below the prefix, so the range gives 16.

What happens when left equals right?

The loop does not run. shift stays 0, and the function returns left << 0, which is left. That is correct, because the range holds one number.

Is there a version without a shift counter?

Yes. Use while right > left: right &= right - 1, then return right. Each step clears the lowest 1 bit of right. When right is no longer larger than left, the remaining 1 bits are the shared prefix. It gives the same answers as the shift loop.

How does this differ from Sum of Two Integers (LC 371)?

Here the answer uses only the leading bits that the two numbers share. In Sum of Two Integers (LC 371), the answer is built from both numbers bit by bit, with carries, so no bit can be ignored.

SWE Reasoning

Spot it

  • The statement asks for the bitwise AND of every integer between two bounds, inclusive.
  • The range can be as large as 2 billion numbers, so a loop over the range is too slow.
  • The statement asks for the common leading bits of two numbers, or the longest shared binary prefix.
  • A small example by hand shows that the answer is always prefix followed by zeros.

The invariant, step by step

  1. Start with shift = 0. left and right are the original ends.
  2. A round runs left >>= 1, right >>= 1 and shift += 1. Now left and right are the original ends with their lowest shift bits removed.
  3. Removing the same number of low bits from both ends keeps their shared prefix. It does not matter which low bits were removed.
  4. The loop stops when left == right. At that moment the value is exactly the shared prefix of the original ends.
  5. Every bit below the prefix is 0 in the AND, because the range contains the number prefix followed by 0111...1 and the number prefix followed by 1000...0.
  6. left << shift puts the prefix back in its original place with shift zeros below it. That is the answer.

Traps

  • return left without << shift. The result is the prefix without its trailing zeros. For left = 5 and right = 7, it returns 1 instead of 4. For left = 22 and right = 30, it returns 1 instead of 16.
  • return left & right of the two ends. A number inside the range can have a 0 where both ends have a 1. For left = 22 and right = 30, this returns 22, but the right answer is 16.
  • Shifting only right. left never changes, so for left > 0 the two values may never become equal. The loop does not end.
  • Looping over the whole range with result &= value. The answer is right, but the range can hold about 2 billion numbers, so the solution is too slow.

Practice

Canonical LeetCode:Bitwise AND of Numbers Range (LC 201)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•