No.1
Two Sum
Given an array of integers and a target, return the indices of the two numbers that add up to the target.
- Method
- One-pass hash map
- Time
O(n)- Space
O(n)- Grade
- Easy
| 1 arraynumsn integers, unsorted | for i, x in enumerate(nums) | c = target − x | c in seen? | yes → return [seen[c], i] no → seen[x] = i, keep going |
|---|---|---|---|---|
| 1 integertargetthe sum we are cooking toward | ||||
| 1 hash mapseenempty; keeps value → index | ||||
Chef's noteThe map is the mise en place: pay O(n) memory once so every lookup afterwards is free. Trading space for time is the whole dish.
No.2
Add Two Numbers
Given two non-empty linked lists whose digits are stored in reverse order, add the two numbers and return the sum as a linked list.
- Method
- Elementary column addition with a carry, poured onto a dummy head
- Time
O(max(m, n))- Space
O(max(m, n))- Grade
- Medium
| 2 listsl1, l2digits in reverse; once spent, val() reads 0 and nxt() None | while l1 or l2 or carry | s = carry + val(l1) + val(l2) carry, d = divmod(s, 10) |
tail.next = ListNode(d) tail = tail.next l1, l2 = nxt(l1), nxt(l2) |
return dummy.next |
|---|---|---|---|---|
| 1 carrycarrystarts at 0, never rises above 1 | ||||
| 1 sentineldummyone throwaway node, made before the walk, discarded after | dummy = ListNode() tail = dummy |
|||
| 1 pointertailrests on dummy, walks right as digits land | ||||
Chef's noteThe carry is a third addend, so keep it in the while condition — a leftover 1 then writes its own digit instead of needing a special case. The dummy head buys the same relief on the other end: you never ask whether this is the first node.
No.3
Longest Substring Without Repeating Characters
Given a string, return the length of the longest substring that contains no repeated character.
- Method
- Sliding window over a last-seen index map
- Time
O(n)- Space
O(min(n, k))- Grade
- Medium
| 1 stringsn characters, taken left to right | for r, ch in enumerate(s) | ch in last and last[ch] ≥ left? | yes → left = last[ch] + 1 no → left holds |
last[ch] = r best = max(best, r − left + 1) |
loop ends return best |
|---|---|---|---|---|---|
| 1 hash maplastempty; keeps char → index last seen | |||||
| 1 pointerleftthe window's near edge, resting at 0 | |||||
| 1 running maxbestseasoned to 0; the longest clean window | |||||
Chef's noteThe left edge never walks backwards: last[ch] says exactly where the window must resume, so both pointers only ever move forward and the whole string is tasted once. The guard last[ch] ≥ left is the seasoning that matters — without it a crumb from an already-discarded prefix drags the edge back and the count goes sour.
No.4
Median of Two Sorted Arrays
Given two sorted arrays, return the median of the two arrays combined, in logarithmic time.
- Method
- Binary search the partition of the shorter array
- Time
O(log min(m, n))- Space
O(1)- Grade
- Hard
| 2 sorted arraysA, Bswapped so A is the shorter; m ≤ n | m, n = len(A), len(B) if m > n: A, B, m, n = B, A, n, m |
half = (m + n + 1) // 2 lo, hi = 0, m |
while lo <= hi: i = (lo + hi) // 2 j = half - i |
aL = A[i-1] if i else -inf aR = A[i] if i < m else inf bL = B[j-1] if j else -inf bR = B[j] if j < n else inf |
aL > bR → hi = i - 1, loop bL > aR → lo = i + 1, loop else → the cut is right |
L = max(aL, bL), R = min(aR, bR) odd → return L even → return (L + R) / 2 |
|---|---|---|---|---|---|---|
| 1 half measurehalf(m + n + 1) // 2 — how many go on the left plate | ||||||
| 2 boundslo, hithe cut in A may fall anywhere from 0 to m | ||||||
| 4 border tastesaL, aR, bL, bRthe values either side of each cut; −∞ off a left end, +∞ off a right | ||||||
| 1 pinch paritym + n odd?one taste, or the average of two | ||||||
Chef's noteNever merge the arrays — only decide where to cut them. Fixing j = half − i makes one cut decide both, so the dish reduces to a binary search for the cut where nothing on the left plate outranks anything on the right. Cutting the shorter array is not only for speed: it is what keeps j inside B, so swap the lengths along with the arrays.
No.5
Longest Palindromic Substring
Given a string, return the longest substring of it that reads the same forwards and backwards.
- Method
- Expand around every center
- Time
O(n²)- Space
O(1)- Grade
- Medium
| 1 stringsn characters, laid out in a single row | n = len(s) for i in range(n) |
for l, r in ((i, i), (i, i+1)): # the letter, then the seam to its right |
while l >= 0 and r < n and s[l] == s[r]: l -= 1; r += 1 |
span = r − l − 1 # both ends overshot | span > len(best) → best = s[l+1:r] after the last center, return best |
|---|---|---|---|---|---|
| 2n − 1 centersievery letter, plus the n − 1 seams between them | |||||
| 2 pointersl, rseated on the center, then stepped outward in lockstep | |||||
| 1 running bestbestthe empty slice, until something beats it | |||||
Chef's noteA palindrome is defined by its middle, so taste outward from the 2n − 1 centers instead of boiling every substring. Each center is seeded twice — once on a letter, once on the seam to its right — because an even-length palindrome has no middle letter to stand on. The pointers always stop one step past the edge, and that overshoot is why the length is r − l − 1.
No.20
Valid Parentheses
Given a string of the characters ( ) [ ] { }, decide whether every bracket is closed by the right kind, in the right order.
- Method
- A stack of the closers you still owe
- Time
O(n)- Space
O(n)- Grade
- Easy
| 1 stringsn brackets, no other characters | for ch in s | ch in pairs? | yes → expect.append(pairs[ch]) no → if not expect or expect.pop() != ch: return False |
loop survived → return not expect |
|---|---|---|---|---|
| 1 lookup tablepairsthree entries, opener → its closer | ||||
| 1 stackexpectempty; the closers still owed, newest on top | ||||
Chef's notePush the closer you owe, not the opener you saw - then every check is one plain equality instead of a table lookup. And the pan must come out empty: leftovers on the stack mean the dish was never finished.
No.21
Merge Two Sorted Lists
Given the heads of two sorted linked lists, splice their nodes into one sorted list and return its head.
- Method
- Two cursors stitched onto a dummy head
- Time
O(m + n)- Space
O(1)- Grade
- Easy
| 1 sorted listl1m nodes ascending; its own cursor, advanced as nodes are taken | while l1 and l2 | l1.val <= l2.val? | yes → tail.next = l1; l1 = l1.next no → tail.next = l2; l2 = l2.next tail = tail.next |
loop ends, one list spent tail.next = l1 or l2 |
return dummy.next |
|---|---|---|---|---|---|
| 1 sorted listl2n nodes ascending; walked alongside, never copied | |||||
| 1 sentineldummyone throwaway node, discarded before serving | dummy = ListNode() tail = dummy |
||||
| 1 pointertailrests on dummy, walks right as nodes land | |||||
Chef's noteThe sentinel is a greased pan: with a node already in hand, the first splice looks exactly like every other one, so no branch is ever spent asking whether the output is still empty. And when one cursor runs dry the survivor is still sorted — tip in the whole remainder rather than ladling it node by node.
No.53
Maximum Subarray
Given an integer array, find the contiguous subarray with the largest sum and return that sum.
- Method
- Kadane's running sum
- Time
O(n)- Space
O(1)- Grade
- Medium
| 1 arraynumsn integers, at least one; some will be bitter | for x in nums | cur = max(x, cur + x) | best = max(best, cur) | loop ends return best |
|---|---|---|---|---|
| 1 running sumcurbest tail ending at x; poured out the moment it sours | cur = 0 | |||
| 1 running maxbestseasoned to −∞, never 0; tasted each pass, never lowered | ||||
Chef's noteNever carry a sour sauce forward: once the running tail goes negative it can only spoil whatever comes next, so cur drops it and restarts at x. Season best with −∞ rather than 0, or an all-negative array serves you an empty pan instead of its least bitter element.
No.121
Best Time to Buy and Sell Stock
Given the daily prices of a stock, return the largest profit from one buy and one later sell, or 0 if no trade turns a profit.
- Method
- Single pass over a running minimum
- Time
O(n)- Space
O(1)- Grade
- Easy
| 1 arraypricesn daily prices, served in order; never re-sorted | for p in prices | cheapest = min(cheapest, p) | gain = p − cheapest best = max(best, gain) |
prices exhausted → return best 0 if no day ever rose |
|---|---|---|---|---|
| 1 running minimumcheapestlowest price seen so far, not its day; seasoned to +∞ | ||||
| 1 running maximumbestprofit banked so far; starts at 0 | ||||
Chef's noteStanding on any day, cheapest already holds the whole past in one number, so a single subtraction values the best earlier purchase. Lower the floor before you weigh the sale and the worst case is a same-day trade worth 0 — which is why no clamp at the end is needed for a market that only falls.
No.206
Reverse Linked List
Given the head of a singly linked list, reverse the list and return the head of the reversed list.
- Method
- Three pointers walked forward
- Time
O(n)- Space
O(1)- Grade
- Easy
| 1 linked listheadn nodes, every arrow pointing forward | curr = head | while curr: | nxt = curr.next | curr.next = prev | prev = curr curr = nxt ↺ back to while |
curr is None → list spent return prev |
|---|---|---|---|---|---|---|
| 1 pointercurrthe node on the board right now | ||||||
| 1 pointernxtscratch; holds the rest of the list for one beat | ||||||
| 1 pointerprevseasoned to None; becomes the new head | ||||||
Chef's noteNever cut the forward arrow until nxt has hold of the rest of the list - that one scratch pointer is the entire recipe. prev trails one node behind curr, and prev is what you plate, not head: head is the tail once you are done, and it points at None.