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•Two Pointers & Sliding Window
HardLC 41

First Missing Positive (LeetCode 41)

Target Frequency:AmazonGoogleMicrosoftMeta

You get an array of integers, nums, in no particular order. It may hold zeros, negative numbers, very large numbers and repeated values. Find the smallest positive whole number (1, 2, 3, ...) that does not appear anywhere in nums, and return it.

Your solution must run in O(n) time, where n is the length of nums, and use only O(1) extra memory beyond the input array. Changing the values inside nums is allowed.

Worked Examples

Example 1
Input:nums = [1,2,0]
Output:3
1021020: no home
Explanation: 1 and 2 are both there, so the first positive number that is absent is 3. The 0 is not positive and plays no part.
Example 2
Input:nums = [3,4,-1,1]
Output:2
3041-12131 present
Explanation: 1 is present but 2 is not. The -1 is ignored, and 3 and 4 do not matter once 2 is missing.
Example 3
Input:nums = [7,8,9,11,12]
Output:1
708192113124
Explanation: No value is 1, so 1 itself is the answer; every value is larger than the length of the array.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 105

  • -231 <= nums[i] <= 231 - 1

Deep-Dive & Conceptual Insights

Core Insight

A value v from 1 to n belongs at index v - 1, so the array can be its own hash table: send each such value home, and the first index that does not hold its own value names the smallest missing positive. Every other value can be ignored, because the answer is always between 1 and n + 1.

Real-World Scenario & Production Applications

Handing out the lowest free number: POSIX requires open() to return the lowest file descriptor that is not in use, and seat, locker or worker-slot numbers are often reused the same way. The numbers in use already say which slot each one fills, so the first empty slot is the answer.

Step-by-Step Execution Trace Table

Example 2, nums = [3,4,-1,1] (n = 4):

StepiValue nums[i]Home nums[i] - 1 holdsActionnums after
103-1swap: 3 goes home to index 2[-1,4,3,1]
20-1(no home)stop: -1 is not in 1..4[-1,4,3,1]
3141swap: 4 goes home to index 3[-1,1,3,4]
411-1swap: 1 goes home to index 0[1,-1,3,4]
51-1(no home)stop[1,-1,3,4]
6233stop: the home already holds 3[1,-1,3,4]
7344stop: the home already holds 4[1,-1,3,4]
8scannums[0] = 1; nums[1] = -1, not 2return 2

Three swaps for four values: each swap put one value in its home for good. With a repeated value, such as the second 2 in [2,3,2,1], the home already holds a copy; the test nums[nums[i] - 1] != nums[i] stops there, while nums[i] != i + 1 would swap the two 2s forever.

Worked on Paper

The Math, Step by Step

1. The number the code looks for

Let nnn be the length of nums. The answer is the smallest positive whole number that is not in nums. Call it mmm.

2. Why the answer is always between 1 and n+1n + 1n+1

The argument counts values. It is a form of the pigeonhole principle: nnn values can match at most nnn different numbers. Take the n+1n + 1n+1 numbers 1,2,…,n+11, 2, \ldots, n + 11,2,…,n+1. nums has only nnn elements, so it can hold at most nnn of those n+1n + 1n+1 numbers. So at least one of 1,…,n+11, \ldots, n + 11,…,n+1 is missing, and

1≤m≤n+11 \le m \le n + 11≤m≤n+1

Every value outside 1…n1 \ldots n1…n can never decide the answer. That includes zero, negative numbers and values greater than nnn. A value greater than nnn could only matter if all of 1…n1 \ldots n1…n were present. Then the answer is n+1n + 1n+1 in any case.

3. The home of each value

Because only the values 1…n1 \ldots n1…n matter, each of them gets a fixed place in the array. The home of value vvv is index v−1v - 1v−1. So value 1 belongs at index 0, and value nnn belongs at index n−1n - 1n−1.

Value nums[i]What the first loop does with it
v<1v < 1v<1 (zero or negative)leaves it where it is
v>nv > nv>nleaves it where it is
1≤v≤n1 \le v \le n1≤v≤n, and its home already holds vvvleaves it where it is
1≤v≤n1 \le v \le n1≤v≤n, and its home holds another valueswaps it into its home, then looks at the value that arrived at index i

After the first loop, every value vvv from 111 to nnn that appears in nums sits in its home. So nums[i] == i + 1 exactly when the value i+1i + 1i+1 is present. The second loop returns the first index iii where this fails, as i+1i + 1i+1. If every home holds its value, all of 1…n1 \ldots n1…n are present, and the code returns n+1n + 1n+1.

4. Why the swaps stop, and the check that handles repeated values

Every swap puts one value into its home. After that, the home holds its own value, so no later swap moves it again. There are nnn homes, so the whole first loop makes at most nnn swaps. The two loops together take O(n)O(n)O(n) time, even though the first loop contains a while.

The condition nums[nums[i] - 1] != nums[i] handles repeated values. Take nums = [1, 1]. At i = 1 the value is 1, and its home, index 0, already holds 1. Without this check the code would swap 1 with 1 forever. With it, the second 1 stays at index 1. The second loop then finds nums[1] = 1, which is not 222, and returns 222.

5. Example 2 by hand

nums = [3,4,-1,1], so n=4n = 4n=4 and the answer is between 1 and 5.

iValue at nums[i]homeArray after the swap
032[-1, 4, 3, 1]
0−1-1−1noneno swap: −1-1−1 is not in 1…41 \ldots 41…4
143[-1, 1, 3, 4]
110[1, -1, 3, 4]
1−1-1−1noneno swap
232no swap: index 2 already holds 3
343no swap: index 3 already holds 4
10-113243missing

The picture shows nums after the first loop. Index 0 holds 1, index 2 holds 3 and index 3 holds 4, so each of these values is in its home. Index 1, marked "missing", holds −1-1−1 instead of 2. It is the first index iii where nums[i] != i + 1. So the second loop returns 1+1=21 + 1 = 21+1=2, the expected output.

6. Example 1 by hand

nums = [1,2,0], so n=3n = 3n=3. Value 1 is already at index 0, and value 2 is already at index 1. The value 0 is not in 1…31 \ldots 31…3. So the first loop makes no swap. The second loop finds nums[0] = 1 and nums[1] = 2 in their homes. At index 2 it finds 0 instead of 3, and it returns 2+1=32 + 1 = 32+1=3, the expected output.

7. From the facts to the code
FactIn firstMissingPositive
only 1…n1 \ldots n1…n can decide the answer1 <= nums[i] <= n
the home of vvv is index v−1v - 1v−1home = nums[i] - 1
stop when the home already holds vvvnums[nums[i] - 1] != nums[i]
index iii should hold i+1i + 1i+1if nums[i] != i + 1: followed by return i + 1
all of 1…n1 \ldots n1…n presentreturn n + 1

The array itself stores the homes, so the code uses O(1)O(1)O(1) extra memory, as the problem requires.

Code Shape
Archetype Code Shape
Python
1A value `v` from 1 to `n` has a home, index `v - 1`: the array can be its own hash table, and the answer is between 1 and `n + 1`.
2Keep this true: an index that holds its own value keeps it, and each swap sends one more value home.
3The shape: `for i in range(n):` with an inner loop that keeps moving the value at `i` to its home while it has one it does not fill yet; then a second loop over the indices, and a last return after it.
4The trap: test whether the home already holds the value, `nums[nums[i] - 1] != nums[i]`, not `nums[i] != i + 1`, or a repeated value swaps forever.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

A hash set would answer "is 1 here? is 2 here?" at once, but this problem allows no extra memory. Cyclic Sort makes the array its own set. A value v from 1 to n has a natural place, index v - 1: its home. Swap every such value into its home, and afterwards each index i either holds i + 1 (that number is present) or holds something else (that number is missing). The smallest missing positive is the first index that fails, plus one, or n + 1 when none fails: n values can fill at most the homes of 1 to n.

🧱 The Analogy: Numbered Lockers

Lockers numbered 1 to n stand in a row, and in front of each one waits a person with a ticket. If your ticket names a locker, you walk to it and swap places with whoever is there, unless that person already holds the same number. People with tickets like 0, -3 or 900 have no locker, so they stay wherever they are pushed. Once nobody can move, the first locker whose person holds a different number is the smallest number nobody had.

🔑 Why It Works

Each swap puts one value into its home, and the while never moves a value that is home, so there are at most n swaps however the loops look. The test that ends the loop is about the home, not about i: when a repeated value finds its home already holding a copy, the swap would exchange two equal values and change nothing, and nums[nums[i] - 1] != nums[i] is what lets the loop stop.

  • Testing the index instead of the home: loop while nums[nums[i] - 1] != nums[i], not while nums[i] != i + 1. With a repeated value, as in [1, 1], the home already holds a copy, the swap changes nothing, and the loop never ends.

  • The one-line swap: save home = nums[i] - 1 first. nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i] writes nums[i] before the second index is computed, so the value lands in the wrong place.

  • Values with no home: test 1 <= nums[i] <= n before reading nums[nums[i] - 1]. A 0 or a negative value gives a negative index, which Python reads from the end of the list without an error.

  • Testing the index instead of the value: the closing scan reads nums[i] != i + 1, not nums[i] != i. A filled home holds i + 1, the value that belongs there, not the bare index i, so comparing against i alone would call every filled home missing.

  • Forgetting n + 1: when every home holds its value, as in [2, 1], the answer is n + 1 = 3, which no index names.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

"The smallest positive whole number (1, 2, 3, ...) that does not appear anywhere in nums", "O(n) time" and "only O(1) extra memory beyond the input array": a missing number, with no room for a hash set, and "changing the values inside nums is allowed". Only 1 to n + 1 can be the answer, and each of 1 to n names an index, so the signal is Cyclic Sort: index v - 1 is the home of v.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

When the swaps end, every value from 1 to n that appears sits at its home, so the first i with nums[i] != i + 1 gives the answer i + 1, or n + 1 if there is none.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • while ... nums[nums[i] - 1] != nums[i]: test the home, not the index (gotcha 1 has the input that loops forever).

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Cyclic Sort and let the array be its own hash table. The answer has to be between 1 and n plus 1, because n values can cover at most the numbers 1 to n, so every other value can be ignored. Every value v from 1 to n has a home, index v minus 1. I walk the array, and while the current value has a home that doesn't hold it yet, I swap it there. Each swap sends one value home for good, so there are at most n swaps in total. Then I scan: the first index i whose value isn't i plus 1 gives the answer i plus 1, and if every home is filled it's n plus 1. The trap is the loop test: I check whether the home already holds v, not whether index i holds i plus 1, or a repeated value would swap forever. That's O(N) time and O(1) extra space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

The outer for i in range(n) runs N times. The inner while looks slow, but each pass of its body is one swap that sends a value v to index v - 1, which holds v from then on, and an index that holds its own value is never swapped again: the while test fails there. So at most N swaps happen in the whole run, not per i, and the loops together make at most 2N tests of the while condition. The second for reads each index at most once and stops at the first gap: O(N). Total: O(N).

SPACE COMPLEXITY

O(1)

The swaps rearrange nums in place, and the code keeps only n, i and home: O(1) extra space, with no recursion. The answer is one integer.

Formal Recurrence Relation

T(N) = N (outer loop) + at most N swaps in all + N (scan) = O(N)

Derivation Progression

Outer loop

O(N)

for i in range(n) visits each index once; the while test runs once more than the swaps made at that i.

All swaps together

at most N

Each swap sends one value to its home v - 1 for good, and a value at home is never moved again, so the swaps across every i add up to at most N.

Scan

O(N)

The second for reads each index at most once and returns at the first i with nums[i] != i + 1.

Total

O(N)

O(N) loop steps, at most N swaps and one scan.

Variable Definitions

NNN

Number of values, len(nums) (at most 10^5)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(1): n, i, home

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N): no value has a home, as in [7,8,9,11,12], so no swap happens, but every index is still visited once

Average Case

O(N)O(N)O(N)

Worst Case

O(N)O(N)O(N): a shuffled 1..N, where every value is swapped home once and the scan reads every index

Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "the smallest positive whole number", "does not appear anywhere in nums", "only O(1) extra memory beyond the input array". A missing number among 1 to n with no room for a set: Cyclic Sort, each value v sent to index v - 1.

CONSTRAINTS & BOUNDS

Up to 10510^5105 values from −231-2^{31}−231 to 231−12^{31} - 1231−1. A hash set of the values takes O(N)O(N)O(N) extra memory and sorting takes O(Nlog⁡N)O(N \log N)O(NlogN) time, both outside the stated bounds; Cyclic Sort works inside nums with one pass of swaps and one scan.

FAANG PRODUCTION TRAPS & EDGE CASES

The input array is the scratch space: a caller that still needs the original order must pass a copy, which brings back the O(N)O(N)O(N) memory the method avoids, so document the mutation. With values from −231-2^{31}−231 to 231−12^{31} - 1231−1, compute nums[i] - 1 only after checking 1 <= nums[i] <= n: in C or Java an unchecked index reads outside the array. The swaps jump to scattered positions, so on arrays much larger than the CPU cache each swap can be a cache miss, where a sequential scan is not.

Core Algorithmic State Invariants

  1. A Short Trace: [3, 4, -1, 1]

At i = 0 the 3 goes to index 2: [-1, 4, 3, 1], and -1 has no home. At i = 1 the 4 goes to index 3: [-1, 1, 3, 4]; the 1 that arrives also has a home, index 0: [1, -1, 3, 4]. Indexes 2 and 3 already hold their values. The scan finds index 1 without a 2, so the answer is 2.

Theory Context•Two Pointers & Sliding Window
HardLC 41

First Missing Positive (LeetCode 41)

Target Frequency:AmazonGoogleMicrosoftMeta

You get an array of integers, nums, in no particular order. It may hold zeros, negative numbers, very large numbers and repeated values. Find the smallest positive whole number (1, 2, 3, ...) that does not appear anywhere in nums, and return it.

Your solution must run in O(n) time, where n is the length of nums, and use only O(1) extra memory beyond the input array. Changing the values inside nums is allowed.

Worked Examples

Example 1
Input:nums = [1,2,0]
Output:3
1021020: no home
Explanation: 1 and 2 are both there, so the first positive number that is absent is 3. The 0 is not positive and plays no part.
Example 2
Input:nums = [3,4,-1,1]
Output:2
3041-12131 present
Explanation: 1 is present but 2 is not. The -1 is ignored, and 3 and 4 do not matter once 2 is missing.
Example 3
Input:nums = [7,8,9,11,12]
Output:1
708192113124
Explanation: No value is 1, so 1 itself is the answer; every value is larger than the length of the array.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 105

  • -231 <= nums[i] <= 231 - 1

Deep-Dive & Conceptual Insights

Core Insight

A value v from 1 to n belongs at index v - 1, so the array can be its own hash table: send each such value home, and the first index that does not hold its own value names the smallest missing positive. Every other value can be ignored, because the answer is always between 1 and n + 1.

Real-World Scenario & Production Applications

Handing out the lowest free number: POSIX requires open() to return the lowest file descriptor that is not in use, and seat, locker or worker-slot numbers are often reused the same way. The numbers in use already say which slot each one fills, so the first empty slot is the answer.

Step-by-Step Execution Trace Table

Example 2, nums = [3,4,-1,1] (n = 4):

StepiValue nums[i]Home nums[i] - 1 holdsActionnums after
103-1swap: 3 goes home to index 2[-1,4,3,1]
20-1(no home)stop: -1 is not in 1..4[-1,4,3,1]
3141swap: 4 goes home to index 3[-1,1,3,4]
411-1swap: 1 goes home to index 0[1,-1,3,4]
51-1(no home)stop[1,-1,3,4]
6233stop: the home already holds 3[1,-1,3,4]
7344stop: the home already holds 4[1,-1,3,4]
8scannums[0] = 1; nums[1] = -1, not 2return 2

Three swaps for four values: each swap put one value in its home for good. With a repeated value, such as the second 2 in [2,3,2,1], the home already holds a copy; the test nums[nums[i] - 1] != nums[i] stops there, while nums[i] != i + 1 would swap the two 2s forever.

Worked on Paper

The Math, Step by Step

1. The number the code looks for

Let nnn be the length of nums. The answer is the smallest positive whole number that is not in nums. Call it mmm.

2. Why the answer is always between 1 and n+1n + 1n+1

The argument counts values. It is a form of the pigeonhole principle: nnn values can match at most nnn different numbers. Take the n+1n + 1n+1 numbers 1,2,…,n+11, 2, \ldots, n + 11,2,…,n+1. nums has only nnn elements, so it can hold at most nnn of those n+1n + 1n+1 numbers. So at least one of 1,…,n+11, \ldots, n + 11,…,n+1 is missing, and

1≤m≤n+11 \le m \le n + 11≤m≤n+1

Every value outside 1…n1 \ldots n1…n can never decide the answer. That includes zero, negative numbers and values greater than nnn. A value greater than nnn could only matter if all of 1…n1 \ldots n1…n were present. Then the answer is n+1n + 1n+1 in any case.

3. The home of each value

Because only the values 1…n1 \ldots n1…n matter, each of them gets a fixed place in the array. The home of value vvv is index v−1v - 1v−1. So value 1 belongs at index 0, and value nnn belongs at index n−1n - 1n−1.

Value nums[i]What the first loop does with it
v<1v < 1v<1 (zero or negative)leaves it where it is
v>nv > nv>nleaves it where it is
1≤v≤n1 \le v \le n1≤v≤n, and its home already holds vvvleaves it where it is
1≤v≤n1 \le v \le n1≤v≤n, and its home holds another valueswaps it into its home, then looks at the value that arrived at index i

After the first loop, every value vvv from 111 to nnn that appears in nums sits in its home. So nums[i] == i + 1 exactly when the value i+1i + 1i+1 is present. The second loop returns the first index iii where this fails, as i+1i + 1i+1. If every home holds its value, all of 1…n1 \ldots n1…n are present, and the code returns n+1n + 1n+1.

4. Why the swaps stop, and the check that handles repeated values

Every swap puts one value into its home. After that, the home holds its own value, so no later swap moves it again. There are nnn homes, so the whole first loop makes at most nnn swaps. The two loops together take O(n)O(n)O(n) time, even though the first loop contains a while.

The condition nums[nums[i] - 1] != nums[i] handles repeated values. Take nums = [1, 1]. At i = 1 the value is 1, and its home, index 0, already holds 1. Without this check the code would swap 1 with 1 forever. With it, the second 1 stays at index 1. The second loop then finds nums[1] = 1, which is not 222, and returns 222.

5. Example 2 by hand

nums = [3,4,-1,1], so n=4n = 4n=4 and the answer is between 1 and 5.

iValue at nums[i]homeArray after the swap
032[-1, 4, 3, 1]
0−1-1−1noneno swap: −1-1−1 is not in 1…41 \ldots 41…4
143[-1, 1, 3, 4]
110[1, -1, 3, 4]
1−1-1−1noneno swap
232no swap: index 2 already holds 3
343no swap: index 3 already holds 4
10-113243missing

The picture shows nums after the first loop. Index 0 holds 1, index 2 holds 3 and index 3 holds 4, so each of these values is in its home. Index 1, marked "missing", holds −1-1−1 instead of 2. It is the first index iii where nums[i] != i + 1. So the second loop returns 1+1=21 + 1 = 21+1=2, the expected output.

6. Example 1 by hand

nums = [1,2,0], so n=3n = 3n=3. Value 1 is already at index 0, and value 2 is already at index 1. The value 0 is not in 1…31 \ldots 31…3. So the first loop makes no swap. The second loop finds nums[0] = 1 and nums[1] = 2 in their homes. At index 2 it finds 0 instead of 3, and it returns 2+1=32 + 1 = 32+1=3, the expected output.

7. From the facts to the code
FactIn firstMissingPositive
only 1…n1 \ldots n1…n can decide the answer1 <= nums[i] <= n
the home of vvv is index v−1v - 1v−1home = nums[i] - 1
stop when the home already holds vvvnums[nums[i] - 1] != nums[i]
index iii should hold i+1i + 1i+1if nums[i] != i + 1: followed by return i + 1
all of 1…n1 \ldots n1…n presentreturn n + 1

The array itself stores the homes, so the code uses O(1)O(1)O(1) extra memory, as the problem requires.

Code Shape
Archetype Code Shape
Python
1A value `v` from 1 to `n` has a home, index `v - 1`: the array can be its own hash table, and the answer is between 1 and `n + 1`.
2Keep this true: an index that holds its own value keeps it, and each swap sends one more value home.
3The shape: `for i in range(n):` with an inner loop that keeps moving the value at `i` to its home while it has one it does not fill yet; then a second loop over the indices, and a last return after it.
4The trap: test whether the home already holds the value, `nums[nums[i] - 1] != nums[i]`, not `nums[i] != i + 1`, or a repeated value swaps forever.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

A hash set would answer "is 1 here? is 2 here?" at once, but this problem allows no extra memory. Cyclic Sort makes the array its own set. A value v from 1 to n has a natural place, index v - 1: its home. Swap every such value into its home, and afterwards each index i either holds i + 1 (that number is present) or holds something else (that number is missing). The smallest missing positive is the first index that fails, plus one, or n + 1 when none fails: n values can fill at most the homes of 1 to n.

🧱 The Analogy: Numbered Lockers

Lockers numbered 1 to n stand in a row, and in front of each one waits a person with a ticket. If your ticket names a locker, you walk to it and swap places with whoever is there, unless that person already holds the same number. People with tickets like 0, -3 or 900 have no locker, so they stay wherever they are pushed. Once nobody can move, the first locker whose person holds a different number is the smallest number nobody had.

🔑 Why It Works

Each swap puts one value into its home, and the while never moves a value that is home, so there are at most n swaps however the loops look. The test that ends the loop is about the home, not about i: when a repeated value finds its home already holding a copy, the swap would exchange two equal values and change nothing, and nums[nums[i] - 1] != nums[i] is what lets the loop stop.

  • Testing the index instead of the home: loop while nums[nums[i] - 1] != nums[i], not while nums[i] != i + 1. With a repeated value, as in [1, 1], the home already holds a copy, the swap changes nothing, and the loop never ends.

  • The one-line swap: save home = nums[i] - 1 first. nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i] writes nums[i] before the second index is computed, so the value lands in the wrong place.

  • Values with no home: test 1 <= nums[i] <= n before reading nums[nums[i] - 1]. A 0 or a negative value gives a negative index, which Python reads from the end of the list without an error.

  • Testing the index instead of the value: the closing scan reads nums[i] != i + 1, not nums[i] != i. A filled home holds i + 1, the value that belongs there, not the bare index i, so comparing against i alone would call every filled home missing.

  • Forgetting n + 1: when every home holds its value, as in [2, 1], the answer is n + 1 = 3, which no index names.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

"The smallest positive whole number (1, 2, 3, ...) that does not appear anywhere in nums", "O(n) time" and "only O(1) extra memory beyond the input array": a missing number, with no room for a hash set, and "changing the values inside nums is allowed". Only 1 to n + 1 can be the answer, and each of 1 to n names an index, so the signal is Cyclic Sort: index v - 1 is the home of v.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

When the swaps end, every value from 1 to n that appears sits at its home, so the first i with nums[i] != i + 1 gives the answer i + 1, or n + 1 if there is none.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • while ... nums[nums[i] - 1] != nums[i]: test the home, not the index (gotcha 1 has the input that loops forever).

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Cyclic Sort and let the array be its own hash table. The answer has to be between 1 and n plus 1, because n values can cover at most the numbers 1 to n, so every other value can be ignored. Every value v from 1 to n has a home, index v minus 1. I walk the array, and while the current value has a home that doesn't hold it yet, I swap it there. Each swap sends one value home for good, so there are at most n swaps in total. Then I scan: the first index i whose value isn't i plus 1 gives the answer i plus 1, and if every home is filled it's n plus 1. The trap is the loop test: I check whether the home already holds v, not whether index i holds i plus 1, or a repeated value would swap forever. That's O(N) time and O(1) extra space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

The outer for i in range(n) runs N times. The inner while looks slow, but each pass of its body is one swap that sends a value v to index v - 1, which holds v from then on, and an index that holds its own value is never swapped again: the while test fails there. So at most N swaps happen in the whole run, not per i, and the loops together make at most 2N tests of the while condition. The second for reads each index at most once and stops at the first gap: O(N). Total: O(N).

SPACE COMPLEXITY

O(1)

The swaps rearrange nums in place, and the code keeps only n, i and home: O(1) extra space, with no recursion. The answer is one integer.

Formal Recurrence Relation

T(N) = N (outer loop) + at most N swaps in all + N (scan) = O(N)

Derivation Progression

Outer loop

O(N)

for i in range(n) visits each index once; the while test runs once more than the swaps made at that i.

All swaps together

at most N

Each swap sends one value to its home v - 1 for good, and a value at home is never moved again, so the swaps across every i add up to at most N.

Scan

O(N)

The second for reads each index at most once and returns at the first i with nums[i] != i + 1.

Total

O(N)

O(N) loop steps, at most N swaps and one scan.

Variable Definitions

NNN

Number of values, len(nums) (at most 10^5)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(1): n, i, home

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N): no value has a home, as in [7,8,9,11,12], so no swap happens, but every index is still visited once

Average Case

O(N)O(N)O(N)

Worst Case

O(N)O(N)O(N): a shuffled 1..N, where every value is swapped home once and the scan reads every index

Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "the smallest positive whole number", "does not appear anywhere in nums", "only O(1) extra memory beyond the input array". A missing number among 1 to n with no room for a set: Cyclic Sort, each value v sent to index v - 1.

CONSTRAINTS & BOUNDS

Up to 10510^5105 values from −231-2^{31}−231 to 231−12^{31} - 1231−1. A hash set of the values takes O(N)O(N)O(N) extra memory and sorting takes O(Nlog⁡N)O(N \log N)O(NlogN) time, both outside the stated bounds; Cyclic Sort works inside nums with one pass of swaps and one scan.

FAANG PRODUCTION TRAPS & EDGE CASES

The input array is the scratch space: a caller that still needs the original order must pass a copy, which brings back the O(N)O(N)O(N) memory the method avoids, so document the mutation. With values from −231-2^{31}−231 to 231−12^{31} - 1231−1, compute nums[i] - 1 only after checking 1 <= nums[i] <= n: in C or Java an unchecked index reads outside the array. The swaps jump to scattered positions, so on arrays much larger than the CPU cache each swap can be a cache miss, where a sequential scan is not.

Core Algorithmic State Invariants

  1. A Short Trace: [3, 4, -1, 1]

At i = 0 the 3 goes to index 2: [-1, 4, 3, 1], and -1 has no home. At i = 1 the 4 goes to index 3: [-1, 1, 3, 4]; the 1 that arrives also has a home, index 0: [1, -1, 3, 4]. Indexes 2 and 3 already hold their values. The scan finds index 1 without a 2, so the answer is 2.

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•