01 / 75·ArrayEasy
Problem

Two Sum

Given an array of integers nums and an integer target, return indices of the two numbers that add up to target. Each input has exactly one solution; you may not use the same element twice.

Input
nums = [2,7,11,15], target = 9
Output
[0,1]
Tap or swipe →LeetCode ↗
Approach
Hash Map · One-Pass

Walk through the array once. For each number x, the value you'd need to pair with it is target - x. Keep a hash map of every number you've already passed, mapping its value to its index. Before storing the current number, check the map for target - x — if it's there, you've found your pair and can return both indices. The map lookup is O(1), which turns the brute-force O(n²) double loop into a single O(n) pass.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
target = 9, nums = [2, 7, 11, 15]

i  nums[i]  need  seen so far  action
0    2       7    {}           store 2 → 0
1    7       2    {2:0}        2 in seen!  return [0, 1] ✓
Tap or swipe → for solution
Solution · Java

Two Sum

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
02 / 75·ArrayEasy
Problem

Best Time to Buy and Sell Stock

You are given an array prices where prices[i] is the price of a stock on day i. Choose one day to buy and a later day to sell to maximize profit. Return 0 if no profit is possible.

Input
prices = [7,1,5,3,6,4]
Output
5
Tap or swipe →LeetCode ↗
Approach
Single-pass min tracking

You can't go back in time — the buy day must come before the sell day. So scan left-to-right while tracking two things: the lowest price seen so far (your best possible buy) and the best profit achievable by selling at today's price (today minus that lowest). Update both at every step. The final answer is the highest profit ever recorded; if prices only fall, it stays at 0.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
prices = [7, 1, 5, 3, 6, 4]

day  price  min so far  profit (price - min)  best
 0     7        7              0                0
 1     1        1              0                0
 2     5        1              4                4
 3     3        1              2                4
 4     6        1              5                5 ★
 5     4        1              3                5

answer: 5  (buy day 1 at $1, sell day 4 at $6)
Tap or swipe → for solution
Solution · Java

Best Time to Buy and Sell Stock

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
03 / 75·ArrayEasy
Problem

Contains Duplicate

Given an integer array nums, return true if any value appears at least twice in the array, and false if every element is distinct.

Input
nums = [1,2,3,1]
Output
true
Tap or swipe →LeetCode ↗
Approach
Hash set membership

Walk through the array once, adding each element to a hash set. The moment you try to add a value that's already in the set, you've found a duplicate — return true immediately. If you finish the loop without ever colliding, every element was unique. Hash sets give O(1) average-case add and lookup, so the entire pass is O(n).

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
nums = [1, 2, 3, 1]

i  nums[i]  set before  add result        action
0    1      {}          new (true)        add
1    2      {1}         new (true)        add
2    3      {1,2}       new (true)        add
3    1      {1,2,3}     duplicate (false) return true ✓
Tap or swipe → for solution
Solution · Java

Contains Duplicate

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
04 / 75·ArrayMedium
Problem

Product of Array Except Self

Given nums, return an array answer where answer[i] equals the product of all elements of nums except nums[i]. Solve in O(n) without using division.

Input
nums = [1,2,3,4]
Output
[24,12,8,6]
Tap or swipe →LeetCode ↗
Approach
Prefix + suffix products

Without using division, you need to know — for each index i — the product of every element to its left and the product of every element to its right; multiplying those two gives the answer. Do it in two passes. Pass 1 (left-to-right): write the running product of everything to the left of i into res[i]. Pass 2 (right-to-left): multiply res[i] by a running product of everything to the right of i. Each cell ends up holding the full product except itself, in O(n) time and O(1) extra space (the output array doesn't count).

Time
O(n)
Space
O(1) extra
Tap or swipe →
Walk-through
nums = [1, 2, 3, 4]

pass 1 (left products):
  i=0  res[0]=1   then left = 1
  i=1  res[1]=1   then left = 2
  i=2  res[2]=2   then left = 6
  i=3  res[3]=6   then left = 24
  res = [1, 1, 2, 6]

pass 2 (multiply by right products, right→left):
  i=3  res[3] *= 1   = 6   right = 4
  i=2  res[2] *= 4   = 8   right = 12
  i=1  res[1] *= 12  = 12  right = 24
  i=0  res[0] *= 24  = 24  right = 24
  res = [24, 12, 8, 6] ✓
Tap or swipe → for solution
Solution · Java

Product of Array Except Self

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
05 / 75·ArrayMedium
Problem

Maximum Subarray

Given an integer array nums, find the contiguous subarray with the largest sum and return that sum. (Kadane's algorithm.)

Input
nums = [-2,1,-3,4,-1,2,1,-5,4]
Output
6
Note
Subarray [4,-1,2,1] has sum 6.
Tap or swipe →LeetCode ↗
Approach
Kadane's algorithm

At each index, ask one question: is the running subarray helping me, or hurting me? If the running sum so far is negative, it can only drag down whatever you add next — drop it and start a fresh subarray at the current element. Otherwise keep it and add the current element. Track the best running sum you've ever seen; that's the answer. One linear pass, no extra space.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]

i  nums[i]  cur = max(nums[i], cur + nums[i])  best
0    -2       -2 (start)                       -2
1     1       max(1,  -2+1=-1) = 1              1
2    -3       max(-3, 1-3=-2)  = -2             1
3     4       max(4,  -2+4=2)  = 4              4
4    -1       max(-1, 4-1=3)   = 3              4
5     2       max(2,  3+2=5)   = 5              5
6     1       max(1,  5+1=6)   = 6              6 ★
7    -5       max(-5, 6-5=1)   = 1              6
8     4       max(4,  1+4=5)   = 5              6

answer: 6  (subarray [4, -1, 2, 1])
Tap or swipe → for solution
Solution · Java

Maximum Subarray

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
06 / 75·ArrayMedium
Problem

Maximum Product Subarray

Given an integer array nums, find the contiguous non-empty subarray within nums that has the largest product, and return that product. The answer is guaranteed to fit in a 32-bit integer.

Input
nums = [2,3,-2,4]
Output
6
Note
The subarray [2,3] has the largest product 6.
Tap or swipe →LeetCode ↗
Approach
Track running max AND min product

If this were sums, you'd just keep a running total and reset whenever it went negative. Products are harder because of one thing: a negative times another negative is a positive — and if both are large in magnitude, the result can be huge. That means a 'bad' running product (very negative) is actually valuable if the next number is also negative, because it can flip into the best answer. So at every index you can't track just one running value — you have to track two: the largest product of any subarray ending at this index, and the smallest (most negative) product of any subarray ending at this index. When you move to the next number `curr`, the best subarray ending there must be one of three things: (1) `curr` by itself, starting a fresh subarray; (2) `curr` multiplied into the previous max, extending a positive streak; (3) `curr` multiplied into the previous min, in case `curr` is negative and flips a deeply-negative streak into a large positive. Take the max of those three for the new running max. Take the min of the exact same three candidates for the new running min — because next iteration, the min you have now might become the biggest answer. Keep a separate `best` variable that takes the max of itself and the running max at every step. That's your answer.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [2, 3, -2, 4]
start: max = 2, min = 2, result = 2

i=1, nums[i]=3
  candidates: 2*3=6, 2*3=6, 3
  max = 6, min = 3, result = 6

i=2, nums[i]=-2
  candidates: 6*-2=-12, 3*-2=-6, -2
  max = -2, min = -12, result = 6
  (notice: min just became very negative — that's the seed for a future flip)

i=3, nums[i]=4
  candidates: -2*4=-8, -12*4=-48, 4
  max = 4, min = -48, result = 6

answer: 6
Tap or swipe → for solution
Solution · Java

Maximum Product Subarray

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
07 / 75·ArrayMedium
Problem

Find Minimum in Rotated Sorted Array

An ascending sorted array of unique elements has been rotated. Find the minimum element in O(log n).

Input
nums = [3,4,5,1,2]
Output
1
Tap or swipe →LeetCode ↗
Approach
Modified binary search

In a rotated sorted array, the minimum sits exactly at the rotation point. Binary search by comparing the middle element to the right boundary. If nums[m] > nums[r], the rotation point (and minimum) lies somewhere strictly to the right of m, so move l = m + 1. Otherwise the minimum is at m or to its left, so set r = m (don't skip m — it could be the answer). When l and r meet, you've cornered the minimum.

Time
O(log n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [3, 4, 5, 1, 2]

l=0, r=4
  m=2, nums[m]=5, nums[r]=2  →  5 > 2, min is right of m  →  l=3
l=3, r=4
  m=3, nums[m]=1, nums[r]=2  →  1 ≤ 2, min is at m or left  →  r=3
l=3, r=3  →  return nums[3] = 1
Tap or swipe → for solution
Solution · Java

Find Minimum in Rotated Sorted Array

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
08 / 75·ArrayMedium
Problem

Search in Rotated Sorted Array

Given a rotated sorted array of distinct integers and a target, return its index, or -1 if not found. Must run in O(log n).

Input
nums = [4,5,6,7,0,1,2], target = 0
Output
4
Tap or swipe →LeetCode ↗
Approach
Binary search with rotation handling

A rotated sorted array always has at least one half (left or right of mid) that's still in plain sorted order. Figure out which half by comparing nums[l] to nums[m]: if nums[l] ≤ nums[m], the left half [l..m] is sorted; otherwise the right half [m..r] is. Once you know which half is clean, you can decide in O(1) whether the target lies inside it (just compare against its endpoints). Discard the other half and continue. Standard binary search, plus one 'which side is sorted?' check per step.

Time
O(log n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [4, 5, 6, 7, 0, 1, 2], target = 0

l=0, r=6
  m=3, nums[m]=7
  left half [4..7] sorted (nums[l]=4 ≤ nums[m]=7)
  target 0 NOT in [4, 7) → search right
  l=4, r=6
    m=5, nums[m]=1
    left half [0..1] sorted (0 ≤ 1)
    target 0 in [0, 1) → search left
    l=4, r=4
      m=4, nums[4]=0 == target → return 4 ✓
Tap or swipe → for solution
Solution · Java

Search in Rotated Sorted Array

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
09 / 75·ArrayMedium
Problem

3Sum

Given nums, return all unique triplets [a,b,c] such that a+b+c == 0. The solution set must not contain duplicate triplets.

Input
nums = [-1,0,1,2,-1,-4]
Output
[[-1,-1,2],[-1,0,1]]
Tap or swipe →LeetCode ↗
Approach
Sort + two-pointer sweep, dedupe via Set

Sort the array first — this enables an efficient two-pointer search. Fix one number nums[i] in the outer loop, then in the remaining sorted suffix use two pointers l (just after i) and r (the end) to find pairs that sum to -nums[i]. If the three-sum is too small, advance l; if too big, retreat r; if it hits zero, record the triplet and step both pointers inward. Duplicates are the only tricky part. Because the array is sorted, equal numbers cluster together, so the same triplet can be generated multiple times — both from a repeated nums[i] in the outer loop and from repeated l/r values inside the sweep. The clean way to handle this is to collect triplets into a Set<List<Integer>>: sorting guarantees each triplet appears in the same canonical order, so equal triplets hash identically and the Set silently drops the duplicates. No fiddly skip-while loops needed. Outer loop O(n), each inner sweep O(n) → O(n²) overall.

Time
O(n²)
Space
O(unique triplets)
Tap or swipe →
Walk-through
nums sorted: [-4, -1, -1, 0, 1, 2]

i=0, fix -4. need pair summing to 4 in [-1,-1,0,1,2]
   l=1, r=5: -1+2=1, too small → l++
   ... never reaches 4, done

i=1, fix -1. need pair summing to 1 in [-1, 0, 1, 2]
   l=2, r=5: -1+2 = 1 ✓  → add [-1,-1,2]; l=3, r=4
   l=3, r=4:  0+1 = 1 ✓  → add [-1, 0, 1]; l=4, r=3 (done)

i=2, fix -1 again. need pair summing to 1 in [0, 1, 2]
   l=3, r=5:  0+2 = 2, too big → r--
   l=3, r=4:  0+1 = 1 ✓  → add [-1, 0, 1] — Set dedupes it
   l=4, r=3 (done)

i=3, fix 0. pair summing to 0 in [1, 2]: none

answer: [[-1,-1,2], [-1,0,1]]
Tap or swipe → for solution
Solution · Java

3Sum

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
10 / 75·ArrayMedium
Problem

Container With Most Water

Given n non-negative integers representing wall heights, find two lines that with the x-axis form a container holding the most water.

Input
height = [1,8,6,2,5,4,8,3,7]
Output
49
Tap or swipe →LeetCode ↗
Approach
Two pointers from the ends

Start with the widest possible container — left pointer at 0, right pointer at n-1. The water area is min(height[l], height[r]) × (r - l). Now shrink: which pointer should you move? Always move the SHORTER wall. Reasoning: the height is capped by the shorter wall, and moving the taller wall inward can only reduce the width without ever raising the height — there's no chance of improvement. Moving the shorter wall at least gives the height a chance to grow. Track the best area as you go.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
          0  1  2  3  4  5  6  7  8

l=0, r=8: min(1,7)=1 × 8 = 8           (best=8)   left shorter → l++
l=1, r=8: min(8,7)=7 × 7 = 49          (best=49)  right shorter → r--
l=1, r=7: min(8,3)=3 × 6 = 18                     right shorter → r--
l=1, r=6: min(8,8)=8 × 5 = 40                     equal, move either → r--
... never improves on 49

answer: 49
Tap or swipe → for solution
Solution · Java

Container With Most Water

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
11 / 75·BinaryMedium
Problem

Sum of Two Integers

Given two integers a and b, return their sum without using the operators + or -. Use bit manipulation: XOR for sum-without-carry, AND+shift for carry.

Input
a = 1, b = 2
Output
3
Tap or swipe →LeetCode ↗
Approach
Bitwise add — XOR for sum, AND<<1 for carry

Reproduce binary addition without using + or -. XOR (^) gives the sum of two bits while ignoring any carry. AND (&) followed by a left shift gives exactly the bits that need to be carried into the next column. Loop: compute the carry, set a = a XOR b (sum so far without carries), then set b = the shifted carry. Repeat until there's nothing left to carry — at that point a holds the final sum.

Time
O(1) — at most ~32 iterations for 32-bit ints
Space
O(1)
Tap or swipe →
Walk-through
a = 5 (101), b = 3 (011)

iter   a       b       a^b      (a&b)<<1
 1   101(5) 011(3)  110(6)    010<<1=100(4)
       ↓ a=110, b=100
 2   110(6) 100(4)  010(2)    100<<1=1000(8)
       ↓ a=010, b=1000
 3   010(2) 1000(8) 1010(10)  000<<1=0
       ↓ a=1010, b=0

b=0 → return a = 10  ✓ (5+3)
Tap or swipe → for solution
Solution · Java

Sum of Two Integers

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
12 / 75·BinaryEasy
Problem

Number of 1 Bits

Write a function that takes an unsigned integer and returns the number of 1 bits (Hamming weight). Trick: n & (n-1) clears the lowest set bit.

Input
n = 11 (0b1011)
Output
3
Tap or swipe →LeetCode ↗
Approach
Brian Kernighan's bit trick

There's a bit-manipulation identity worth memorising: the expression n & (n - 1) always clears the lowest 1-bit of n, leaving every other bit untouched. So if you keep applying that and counting, by the time n becomes 0 you've cleared every 1-bit, and your counter equals the original number of 1-bits. This is faster than checking all 32 bits one by one because you only do work for the bits that are actually set.

Time
O(k) where k = #set bits
Space
O(1)
Tap or swipe →
Walk-through
n = 11 = 1011₂

iter   n            n - 1        n & (n - 1)    count
 1    1011 (11)    1010 (10)     1010 (10)        1
 2    1010 (10)    1001  (9)     1000  (8)        2
 3    1000  (8)    0111  (7)     0000  (0)        3
                                    ↑ n = 0  →  return 3
Tap or swipe → for solution
Solution · Java

Number of 1 Bits

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
13 / 75·BinaryEasy
Problem

Counting Bits

Given n, return an array of length n+1 where ans[i] is the number of 1's in the binary representation of i. Solve in O(n).

Input
n = 5
Output
[0,1,1,2,1,2]
Tap or swipe →LeetCode ↗
Approach
DP using i >> 1 subproblem

Notice that i and i >> 1 (i with its lowest bit dropped) have the same number of 1-bits, except for that one bit you might have dropped. So bits(i) = bits(i >> 1) + (i & 1). Build the result array bottom-up: dp[0] = 0, then for each later i compute dp[i] in O(1) from an already-filled smaller index. One pass, no per-number bit counting.

Time
O(n)
Space
O(n) for the result
Tap or swipe →
Walk-through
n = 5

i  binary  i >> 1  i & 1  dp[i] = dp[i>>1] + (i&1)
0   000     -        -     0
1   001     0        1     dp[0] + 1 = 1
2   010     1        0     dp[1] + 0 = 1
3   011     1        1     dp[1] + 1 = 2
4   100     2        0     dp[2] + 0 = 1
5   101     2        1     dp[2] + 1 = 2

answer: [0, 1, 1, 2, 1, 2]
Tap or swipe → for solution
Solution · Java

Counting Bits

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
14 / 75·BinaryEasy
Problem

Missing Number

Given an array nums containing n distinct numbers in [0, n], return the only number in the range that is missing.

Input
nums = [3,0,1]
Output
2
Tap or swipe →LeetCode ↗
Approach
Sum formula

The numbers 0 through n add up to n(n+1)/2 — the closed-form sum of the first n+1 integers. Subtract every number actually present in the array from that expected total, and whatever's left is the missing number. One pass, O(1) extra space, no hashing or sorting needed.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [3, 0, 1], n = 3

expected sum = 3 * 4 / 2 = 6

6 - 3 = 3
3 - 0 = 3
3 - 1 = 2

answer: 2
Tap or swipe → for solution
Solution · Java

Missing Number

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
15 / 75·BinaryEasy
Problem

Reverse Bits

Reverse the bits of a 32-bit unsigned integer. Shift the answer left and OR in the lowest bit of n; then shift n right.

Input
n = 0b00000010100101000001111010011100
Output
0b00111001011110000010100101000000
Tap or swipe →LeetCode ↗
Approach
Shift-and-OR for 32 iterations

Build the reversed result one bit at a time. On each iteration: shift res left by 1 (making room for a new bit at position 0), then OR in the lowest bit of n. Then unsigned-shift n right by 1 to expose the next bit. After 32 passes, every bit of n has migrated to its mirrored position in res.

Time
O(1) — exactly 32 iterations
Space
O(1)
Tap or swipe →
Walk-through
(showing the lowest 4 bits for clarity; in real code 32 iterations)

n = ...1101

iter   res before  n & 1  res after (shift+or)  n after >>>=1
 1     0000        1      0001                  ...110
 2     0001        0      0010                  ...11
 3     0010        1      0101                  ...1
 4     0101        1      1011                  ...0

each bit of n ends up at its mirror position:
  original bit 0 lands at bit 31, bit 1 at bit 30, etc.
Tap or swipe → for solution
Solution · Java

Reverse Bits

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
16 / 75·DPEasy
Problem

Climbing Stairs

You can climb 1 or 2 steps at a time. How many distinct ways can you reach step n? (Fibonacci.)

Input
n = 3
Output
3
Tap or swipe →LeetCode ↗
Approach
1-D DP · Fibonacci

Think backwards from step n. The very last move you made to land on n was either a 1-step (so you came from step n-1) or a 2-step (you came from n-2). Those are the only two options, and they don't overlap, so the number of ways to reach n equals the ways to reach n-1 plus the ways to reach n-2. That recurrence is exactly the Fibonacci sequence. Build it bottom-up from steps 0 and 1 — you only need to remember the previous two values, so it's O(1) extra space.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
n = 5

step:    1   2   3   4   5
ways:    1   2   3   5   8
                 ↑   ↑   ↑
              1+2 2+3 3+5

state machine:
  a, b = 1, 1                (ways to reach steps 0 and 1)
  for i = 2..n:
      a, b = b, a + b
  return b
Tap or swipe → for solution
Solution · Java

Climbing Stairs

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
17 / 75·DPMedium
Problem

Coin Change

Given coin denominations and an amount, return the fewest number of coins needed to make up that amount. Return -1 if impossible.

Input
coins = [1,2,5], amount = 11
Output
3
Tap or swipe →LeetCode ↗
Approach
Bottom-up DP over amounts

Define dp[i] = the fewest coins needed to make amount i. Base case: dp[0] = 0. For every i from 1 to amount, try each coin c — if i - c is reachable, then dp[i] could be dp[i-c] + 1. Take the minimum across all coin choices. Initialise the array with a sentinel (amount + 1, larger than any possible answer) so 'unreachable' shows up naturally. At the end, dp[amount] is your answer (or -1 if it's still the sentinel).

Time
O(amount × #coins)
Space
O(amount)
Tap or swipe →
Walk-through
coins = [1, 2, 5], amount = 11

dp:  [0, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞]

i=1: try 1 → dp[0]+1 = 1                     dp[1]=1
i=2: try 1 → dp[1]+1 = 2; try 2 → dp[0]+1=1  dp[2]=1
i=3: try 1 → dp[2]+1 = 2; try 2 → dp[1]+1=2  dp[3]=2
i=4: try 1 → dp[3]+1 = 3; try 2 → dp[2]+1=2  dp[4]=2
i=5: try 1 → 3; try 2 → 3; try 5 → 1         dp[5]=1
...
i=11: try 1 → dp[10]+1=3; try 2 → dp[9]+1=4; try 5 → dp[6]+1=3
                                              dp[11]=3

answer: 3  (e.g. 5 + 5 + 1)
Tap or swipe → for solution
Solution · Java

Coin Change

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
18 / 75·DPMedium
Problem

Longest Increasing Subsequence

Given an integer array nums, return the length of the longest strictly increasing subsequence. Patience sort gives O(n log n).

Input
nums = [10,9,2,5,3,7,101,18]
Output
4
Tap or swipe →LeetCode ↗
Approach
Patience sorting — binary search into 'tails'

Maintain an array tails where tails[k] holds the smallest possible tail value of any increasing subsequence of length k+1 seen so far. For each new x, binary-search the leftmost position pos where tails[pos] >= x. If you find one, overwrite tails[pos] with x — you've made an increasing subsequence of that length end with a smaller value, leaving more room to extend later. If x is larger than every tail, append it (longest subsequence grew by 1). The contents of tails aren't a valid LIS, but its length always equals the LIS length. O(n log n) total.

Time
O(n log n)
Space
O(n)
Tap or swipe →
Walk-through
nums = [10, 9, 2, 5, 3, 7, 101, 18]

x=10  binary search in []        → pos=0, append.  tails=[10]
x=9   pos in [10] for ≥9         → pos=0, replace. tails=[9]
x=2   pos in [9]                 → pos=0, replace. tails=[2]
x=5   pos in [2] for ≥5          → pos=1, append.  tails=[2,5]
x=3   pos in [2,5] for ≥3        → pos=1, replace. tails=[2,3]
x=7   pos in [2,3] for ≥7        → pos=2, append.  tails=[2,3,7]
x=101 pos in [2,3,7] for ≥101    → pos=3, append.  tails=[2,3,7,101]
x=18  pos in [2,3,7,101] for ≥18 → pos=3, replace. tails=[2,3,7,18]

answer: tails.length = 4
Tap or swipe → for solution
Solution · Java

Longest Increasing Subsequence

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
19 / 75·DPMedium
Problem

Longest Common Subsequence

Given two strings text1 and text2, return the length of their longest common subsequence (not necessarily contiguous).

Input
text1 = "abcde", text2 = "ace"
Output
3
Tap or swipe →LeetCode ↗
Approach
2-D DP over string indices

Build a table dp where dp[i][j] is the LCS length of a's first i characters and b's first j characters. Recurrence: if the latest characters match (a[i-1] == b[j-1]), dp[i][j] = dp[i-1][j-1] + 1 — extend the previous match. Otherwise, drop one character from either string and take the better option: dp[i][j] = max(dp[i-1][j], dp[i][j-1]). Base row and column are zero (an empty string has no common subsequence). The answer is dp[m][n].

Time
O(m·n)
Space
O(m·n)
Tap or swipe →
Walk-through
a = "abcde", b = "ace"

       ""  a  c  e
   "":  0  0  0  0
    a:  0  1  1  1
    b:  0  1  1  1
    c:  0  1  2  2
    d:  0  1  2  2
    e:  0  1  2  3

dp[5][3] = 3  (the LCS is "ace")
Tap or swipe → for solution
Solution · Java

Longest Common Subsequence

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
20 / 75·DPMedium
Problem

Word Break

Given string s and a dictionary of words, return true if s can be segmented into a space-separated sequence of dictionary words.

Input
s = "leetcode", wordDict = ["leet","code"]
Output
true
Tap or swipe →LeetCode ↗
Approach
1-D DP over substring endings

Define dp[i] = true if the prefix s[0..i) can be split entirely into dictionary words. Base case: dp[0] = true (the empty prefix is trivially valid). For each i, try every split point j < i: if dp[j] is true and the substring s[j..i) is in the dictionary, then dp[i] is true as well — break early. Answer is dp[s.length]. Putting the dictionary in a HashSet makes each membership check O(1).

Time
O(n² · L) where L = avg word length
Space
O(n)
Tap or swipe →
Walk-through
s = "leetcode", wordDict = {"leet", "code"}

dp = [T, F, F, F, F, F, F, F, F]   (indices 0..8)

i=1 "l"      no split works             F
i=2 "le"     no                          F
i=3 "lee"    no                          F
i=4 "leet"   dp[0]=T and "leet" in set  T
i=5 "leetc"  dp[4]=T and "c" in set? no  F
i=6, i=7     no                          F
i=8 "leetcode" dp[4]=T and "code" in set T

answer: dp[8] = true
Tap or swipe → for solution
Solution · Java

Word Break

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
21 / 75·DPMedium
Problem

Combination Sum IV

Given an array of distinct positive integers nums and a target, return the number of possible orderings (sequences) that sum to target.

Input
nums = [1,2,3], target = 4
Output
7
Tap or swipe →LeetCode ↗
Approach
1-D DP — order matters

Despite the name, this counts the number of ordered SEQUENCES of nums that sum to target (so [1,2] and [2,1] are different). Define dp[i] = number of sequences summing to i. Base: dp[0] = 1 (one empty sequence sums to 0). For each total i from 1 to target, sum dp[i - n] over every n in nums — each contributes 'all the ways to make i - n, then append n'. Critically, the OUTER loop is over totals (not coins) — that ordering is what makes sequences count rather than combinations.

Time
O(target · n)
Space
O(target)
Tap or swipe →
Walk-through
nums = [1, 2, 3], target = 4

dp[0] = 1

i=1: dp[0] = 1                              dp[1] = 1
i=2: dp[1] + dp[0] = 2                      dp[2] = 2
i=3: dp[2] + dp[1] + dp[0] = 4              dp[3] = 4
i=4: dp[3] + dp[2] + dp[1] = 4 + 2 + 1 = 7  dp[4] = 7

answer: 7
sequences: [1,1,1,1], [1,1,2], [1,2,1], [2,1,1], [2,2], [1,3], [3,1]
Tap or swipe → for solution
Solution · Java

Combination Sum IV

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
22 / 75·DPMedium
Problem

House Robber

Given non-negative integers representing money in each house, return the max you can rob without robbing two adjacent houses.

Input
nums = [2,7,9,3,1]
Output
12
Tap or swipe →LeetCode ↗
Approach
1-D DP — pick or skip

At each house i you have two choices: rob it (then add nums[i] to whatever you'd best collected up to house i-2 — you can't touch i-1 because it's adjacent) or skip it (keep your best total through house i-1). So dp[i] = max(dp[i-1], dp[i-2] + nums[i]). You only ever need the previous two values, so roll two variables prev and curr instead of allocating a full array.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [2, 7, 9, 3, 1]

step  nums  prev  curr  next = max(curr, prev + nums)
 0      2     0     0    max(0, 0+2) = 2
 1      7     0     2    max(2, 0+7) = 7
 2      9     2     7    max(7, 2+9) = 11
 3      3     7    11    max(11, 7+3) = 11
 4      1    11    11    max(11, 11+1) = 12

answer: 12   (rob houses 0, 2, 4 → 2 + 9 + 1)
Tap or swipe → for solution
Solution · Java

House Robber

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
23 / 75·DPMedium
Problem

House Robber II

Same as House Robber, but the houses are arranged in a circle (first and last are adjacent). Run House Robber on nums[1:] and nums[:-1].

Input
nums = [2,3,2]
Output
3
Tap or swipe →LeetCode ↗
Approach
Run linear House Robber twice

Same recurrence as House Robber, but the houses are arranged in a circle, so the first and last houses are now neighbours and can't both be robbed. Reduce to two simpler linear problems: (a) rob within nums[0..n-2] (last house excluded) and (b) rob within nums[1..n-1] (first house excluded). Each becomes a regular linear House Robber. The answer is the larger of the two. Handle the n == 1 edge case separately (return nums[0]).

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [2, 3, 2]   (circular: 2 ↔ 3 ↔ 2 ↔ 2)

range A: nums[0..1] = [2, 3]
  linear robber: max takings = 3
range B: nums[1..2] = [3, 2]
  linear robber: max takings = 3

answer: max(3, 3) = 3

(can't rob both 2's because they're adjacent in the circle)
Tap or swipe → for solution
Solution · Java

House Robber II

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
24 / 75·DPMedium
Problem

Decode Ways

A message of digits encodes letters: 'A'=1 ... 'Z'=26. Return the number of ways to decode the string.

Input
s = "12"
Output
2
Note
'AB' or 'L'
Tap or swipe →LeetCode ↗
Approach
1-D DP with one- and two-digit transitions

Define dp[i] = number of ways to decode the prefix s[0..i). Base: dp[0] = 1 (empty has one decoding — itself). For each i, look at the last one or two digits. If s[i-1] is '1'..'9', it can stand alone as a letter — add dp[i-1]. If s[i-2..i] forms a number 10..26, it can be one two-letter decoding — add dp[i-2]. Watch for the leading-zero edge case: if s[0] == '0', there are zero valid decodings overall.

Time
O(n)
Space
O(n) — or O(1) if you roll variables
Tap or swipe →
Walk-through
s = "226"

dp[0] = 1  (empty)
dp[1] = 1  (just "2")

i=2: s[1]='2' single ok → dp[1] = 1
     s[0..2]="22" two-digit (10-26) → dp[0] = 1
     dp[2] = 1 + 1 = 2          ("2,2" or "22")

i=3: s[2]='6' single ok → dp[2] = 2
     s[1..3]="26" two-digit ok → dp[1] = 1
     dp[3] = 2 + 1 = 3          ("2,2,6", "22,6", "2,26")

answer: 3
Tap or swipe → for solution
Solution · Java

Decode Ways

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
25 / 75·DPMedium
Problem

Unique Paths

On an m x n grid, a robot at top-left moves only right or down. How many distinct paths reach the bottom-right?

Input
m = 3, n = 7
Output
28
Tap or swipe →LeetCode ↗
Approach
2-D DP, compressed to a 1-D row

From any cell you can only move right or down, so the number of paths to (i, j) equals paths to (i-1, j) plus paths to (i, j-1). The top row and left column are all 1 (only one way along an edge). You only ever need the current row and the row above, so keep one 1-D array of length n and update it in place: dp[j] += dp[j-1] computes 'paths to (i, j) = paths to (i-1, j) (already in dp[j]) + paths to (i, j-1) (just computed in dp[j-1])'.

Time
O(m·n)
Space
O(n)
Tap or swipe →
Walk-through
m = 3, n = 7

initial dp = [1, 1, 1, 1, 1, 1, 1]   (top row)

row i=1:  dp[j] += dp[j-1] across j=1..6
          dp = [1, 2, 3, 4, 5, 6, 7]

row i=2:  dp[j] += dp[j-1] across j=1..6
          dp = [1, 3, 6, 10, 15, 21, 28]

answer: dp[6] = 28
Tap or swipe → for solution
Solution · Java

Unique Paths

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
26 / 75·DPMedium
Problem

Jump Game

Given nums where nums[i] is the max jump length from index i, can you reach the last index? Greedy: track furthest reach.

Input
nums = [2,3,1,1,4]
Output
true
Tap or swipe →LeetCode ↗
Approach
Greedy reach tracking

Walk left-to-right, tracking 'reach' — the farthest index you can possibly land on so far. At each index i, first check if i > reach; if so, you've hit a position that can't be reached and you're stuck — return false. Otherwise update reach = max(reach, i + nums[i]) (the farthest you can jump from this index). If you make it through the whole loop, you reached every index, including the last one.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
nums = [2, 3, 1, 1, 4]

i=0  reach=0  i ≤ reach  reach = max(0, 0+2) = 2
i=1  reach=2  i ≤ reach  reach = max(2, 1+3) = 4
i=2  reach=4  i ≤ reach  reach = max(4, 2+1) = 4
i=3  reach=4  i ≤ reach  reach = max(4, 3+1) = 4
i=4  reach=4  i ≤ reach  reach = max(4, 4+4) = 8

never failed → return true
Tap or swipe → for solution
Solution · Java

Jump Game

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
27 / 75·GraphMedium
Problem

Clone Graph

Given a reference to a node in a connected undirected graph, return a deep copy of the graph. Use DFS + a Map from original to clone.

Input
adjList = [[2,4],[1,3],[2,4],[1,3]]
Output
deep copy
Tap or swipe →LeetCode ↗
Approach
DFS with original→copy hash map

Walk the original graph with DFS, building copies as you go. Keep a HashMap from each original node to its newly created clone — this acts as both the 'visited' marker AND the way to return the same clone whenever you encounter the same original node twice (essential because graphs can have cycles). For each original node: if it's already in the map, return the cached copy. Otherwise create a new node with the same value, store it in the map BEFORE recursing into neighbours (so cycles short-circuit on the second visit), then recursively clone each neighbour and attach.

Time
O(V + E)
Space
O(V)
Tap or swipe →
Walk-through
graph: 1 — 2
       |   |
       4 — 3

dfs(1):
  copy1 = {val:1}, map = {1: copy1}
  recurse into neighbours [2, 4]:
    dfs(2):
      copy2 = {val:2}, map += {2: copy2}
      neighbours [1, 3]:
        dfs(1) → already in map, return copy1
        dfs(3) → build copy3, neighbours include 2 (cached) and 4
      copy2.neighbors = [copy1, copy3]
    dfs(4):
      copy4 = {val:4}, similar walk
  copy1.neighbors = [copy2, copy4]

return copy1
Tap or swipe → for solution
Solution · Java

Clone Graph

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
28 / 75·GraphMedium
Problem

Course Schedule

n courses labeled 0..n-1 with prerequisite pairs [a,b] meaning b must precede a. Return true if all courses can be finished (no cycles). Use Kahn's topological sort.

Input
n = 2, prerequisites = [[1,0]]
Output
true
Tap or swipe →LeetCode ↗
Approach
Topological sort (Kahn's BFS)

Model courses as nodes and each prerequisite [a, b] as a directed edge b → a (b must come before a). The schedule is feasible iff the graph has no cycles, i.e. you can topologically sort it. Kahn's algorithm: compute each node's in-degree (number of unmet prerequisites). Push every zero-in-degree node into a queue, then repeatedly pop one (mark it done) and decrement the in-degrees of its dependents — any that hit zero are queued. Count how many you process; if it equals n, you finished all courses. If a cycle exists, some nodes never reach zero and stay stuck.

Time
O(V + E)
Space
O(V + E)
Tap or swipe →
Walk-through
n = 4, prereqs = [[1,0], [2,0], [3,1], [3,2]]

graph: 0 → 1 → 3
       0 → 2 → 3

indeg: 0→0, 1→1, 2→1, 3→2
queue: [0],  done = 0

pop 0, done=1. decrement 1 (→0, queue), 2 (→0, queue)
queue: [1, 2]

pop 1, done=2. decrement 3 (→1)
pop 2, done=3. decrement 3 (→0, queue)
queue: [3]

pop 3, done=4

done == n → return true
Tap or swipe → for solution
Solution · Java

Course Schedule

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
29 / 75·GraphMedium
Problem

Pacific Atlantic Water Flow

Given an m x n matrix of heights, water flows to a neighbor if its height is <=. Return cells from which water can flow to BOTH the Pacific (top/left) and Atlantic (bottom/right).

Input
heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output
[[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
Tap or swipe →LeetCode ↗
Approach
Reverse DFS from each ocean's border

Don't simulate water flowing FROM each cell TO an ocean — that's too expensive. Reverse the perspective: pretend water flows uphill in your model. Start a DFS from every cell on the Pacific border (top row + left column) and mark every cell you can reach by only stepping to neighbours of equal-or-greater height. Do the same from the Atlantic border (bottom row + right column). The cells reachable in BOTH searches are exactly those from which water can drain to both oceans. Two passes, O(m·n) total.

Time
O(m·n)
Space
O(m·n)
Tap or swipe →
Walk-through
heights:
  1 2 2 3 5
  3 2 3 4 4
  2 4 5 3 1
  6 7 1 4 5
  5 1 1 2 4

Pacific touches the top row and left column.
Atlantic touches the bottom row and right column.

DFS from each Pacific border cell, climbing to ≥-height neighbours:
  marks every cell that water from this cell could flow to Pacific FROM.
DFS from each Atlantic border cell, same rule.

Cells marked by BOTH searches:
  [[0,4], [1,3], [1,4], [2,2], [3,0], [3,1], [4,0]]
Tap or swipe → for solution
Solution · Java

Pacific Atlantic Water Flow

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
30 / 75·GraphMedium
Problem

Number of Islands

Given an m x n grid of '1' (land) and '0' (water), return the number of islands. An island is a group of '1's connected 4-directionally.

Input
grid = [["1","1","0"],["1","0","0"],["0","0","1"]]
Output
2
Tap or swipe →LeetCode ↗
Approach
DFS flood-fill

Scan the grid cell by cell. Every time you find a '1' you haven't visited yet, that's a new island, so increment your counter. Then 'sink' that whole island by running DFS from that cell, flipping every connected '1' to '0' as you go (4-directional neighbours only). Because you've turned visited land into water, when your outer scan reaches those cells later it'll skip them — so each island is counted exactly once. You don't need a separate visited array; the grid itself records what you've seen.

Time
O(m·n)
Space
O(m·n) recursion stack worst case
Tap or swipe →
Walk-through
grid (scan row by row):

1 1 0
1 0 0
0 0 1

(0,0) = '1'  →  island #1, sink it
. . 0     flood: (0,0) → (0,1) → (1,0)
. 0 0
0 0 1

continue scanning... reach (2,2) = '1'
. . 0     island #2, sink (2,2)
. 0 0
0 0 .

answer: 2
Tap or swipe → for solution
Solution · Java

Number of Islands

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
31 / 75·GraphMedium
Problem

Longest Consecutive Sequence

Given an unsorted array, return the length of the longest consecutive elements sequence. Solve in O(n). Only start counting from sequence starts.

Input
nums = [100,4,200,1,3,2]
Output
4
Tap or swipe →LeetCode ↗
Approach
Hash set + only count from sequence starts

Throw all numbers into a HashSet for O(1) membership checks. Then for each number n in the set, only START counting if n - 1 is NOT in the set — that means n is the smallest of its consecutive run. From there, walk upward (n+1, n+2, ...) while the next number exists, counting the length. The 'only start from sequence starts' rule keeps the inner loop's TOTAL work O(n) across all iterations, even though it looks like nested loops.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
nums = [100, 4, 200, 1, 3, 2]
set  = {100, 4, 200, 1, 3, 2}

for each n in set:
  100 → 99 not in set, start.  100 → 101? no. len=1
  4   → 3 IN set, skip (not a start)
  200 → 199 not in set, start. 200 → 201? no. len=1
  1   → 0 not in set, start.   1, 2, 3, 4 → 5? no. len=4 ★
  3   → 2 IN set, skip
  2   → 1 IN set, skip

answer: 4
Tap or swipe → for solution
Solution · Java

Longest Consecutive Sequence

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
32 / 75·GraphHard
Problem

Alien Dictionary

Given a sorted list of words from an alien language, derive the order of letters. Build a graph from each adjacent word pair and topo-sort.

Input
words = ["wrt","wrf","er","ett","rftt"]
Output
"wertf"
Tap or swipe →LeetCode ↗
Approach
Build edges from adjacent word pairs, then topological sort

Compare each pair of adjacent words. The first position where they differ tells you one ordering rule: that character of the earlier word must come before that character of the later word. Treat these as directed edges in a graph over the alphabet. Then topologically sort with Kahn's BFS. Two edge cases: if one word is a prefix of an EARLIER longer word (e.g. 'apple' before 'app'), that's invalid — return empty string. After topological sort, if the result is shorter than the alphabet you collected, there's a cycle — also return empty string.

Time
O(C) where C = total chars across all words
Space
O(C)
Tap or swipe →
Walk-through
words = ["wrt", "wrf", "er", "ett", "rftt"]

compare adjacent pairs for first differing char:
  wrt vs wrf  → t before f
  wrf vs er   → w before e
  er  vs ett  → r before t
  ett vs rftt → e before r

graph:  w → e → r → t → f

indeg: w=0, e=1, r=1, t=1, f=1
queue: [w]
  pop w → "w";    indeg e → 0,  queue [e]
  pop e → "we";   indeg r → 0,  queue [r]
  pop r → "wer";  indeg t → 0,  queue [t]
  pop t → "wert"; indeg f → 0,  queue [f]
  pop f → "wertf"

answer: "wertf"
Tap or swipe → for solution
Solution · Java

Alien Dictionary

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
33 / 75·GraphMedium
Problem

Graph Valid Tree

Given n nodes (0..n-1) and a list of edges, decide if these edges form a valid tree. A valid tree has exactly n-1 edges, is connected, and has no cycles.

Input
n = 5, edges = [[0,1],[0,2],[0,3],[1,4]]
Output
true
Tap or swipe →LeetCode ↗
Approach
Union-Find with edge count

An undirected graph on n nodes is a tree iff it has exactly n - 1 edges AND is connected. Equivalently: exactly n - 1 edges AND no cycles. Use Union-Find: walk through edges and union the endpoints. If you ever try to union two nodes that already share a root, you've found a cycle — return false. If you survive every edge with the count check passing too, the graph is connected and acyclic — a valid tree.

Time
O(n · α(n)) ≈ O(n)
Space
O(n)
Tap or swipe →
Walk-through
n = 5, edges = [[0,1], [0,2], [0,3], [1,4]]

#edges = 4 = n - 1 ✓ (passes the count check)

parent: [0, 1, 2, 3, 4]

[0,1]: roots 0, 1 differ. union → parent[0]=1
[0,2]: find(0)=1, find(2)=2 differ. union → parent[1]=2
[0,3]: find(0)=2, find(3)=3 differ. union → parent[2]=3
[1,4]: find(1)=3, find(4)=4 differ. union → parent[3]=4

never collided → return true
Tap or swipe → for solution
Solution · Java

Graph Valid Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
34 / 75·GraphMedium
Problem

Number of Connected Components

Given n nodes and an array of edges in an undirected graph, return the number of connected components. Union-Find: start with n components and decrement on each successful union.

Input
n = 5, edges = [[0,1],[1,2],[3,4]]
Output
2
Tap or swipe →LeetCode ↗
Approach
Union-Find component counter

Start with n disconnected nodes — that's n components. Walk through every edge and union its endpoints; each successful union (different roots) merges two components into one, so decrement the counter. Edges between already-connected nodes leave the count alone. The final counter is your answer.

Time
O((n + e) · α(n)) ≈ O(n + e)
Space
O(n)
Tap or swipe →
Walk-through
n = 5, edges = [[0,1], [1,2], [3,4]]

count = 5, parent = [0, 1, 2, 3, 4]

[0,1]: roots 0, 1 differ. union, count = 4
[1,2]: find(1)=1, find(2)=2 differ. union, count = 3
[3,4]: roots 3, 4 differ. union, count = 2

answer: 2
Tap or swipe → for solution
Solution · Java

Number of Connected Components

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
35 / 75·IntervalMedium
Problem

Insert Interval

Given non-overlapping intervals sorted by start, insert a new interval (merging if necessary) and return the result.

Input
intervals = [[1,3],[6,9]], newInterval = [2,5]
Output
[[1,5],[6,9]]
Tap or swipe →LeetCode ↗
Approach
Three-phase walk through sorted intervals

Intervals are already sorted by start. Walk through in three phases. Phase 1: copy any interval that ends strictly before newInterval starts — these don't overlap. Phase 2: any interval whose start is ≤ newInterval's end overlaps — keep merging by extending newInterval's bounds to absorb them. Phase 3: copy any remaining intervals that start after newInterval ends. Push newInterval at the boundary between phases 2 and 3. O(n) total.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
intervals = [[1,3], [6,9]], new = [2,5]

phase 1 (ends < 2):
  [1,3]: 3 < 2? no  → skip phase 1

phase 2 (starts ≤ 5):
  [1,3]: starts 1 ≤ 5, overlap. new = [min(2,1), max(5,3)] = [1,5]
  [6,9]: starts 6 ≤ 5? no, exit phase 2

push new: [1,5]

phase 3:
  [6,9]: copy

result: [[1,5], [6,9]]
Tap or swipe → for solution
Solution · Java

Insert Interval

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
36 / 75·IntervalMedium
Problem

Merge Intervals

Given an array of intervals, merge all overlapping intervals and return the merged list. Sort by start; merge by extending the last interval's end.

Input
intervals = [[1,3],[2,6],[8,10],[15,18]]
Output
[[1,6],[8,10],[15,18]]
Tap or swipe →LeetCode ↗
Approach
Sort + linear sweep

First sort the intervals by their start time. Then walk through them in order, maintaining a 'merged so far' list that starts with the first interval. For each new interval, peek at the last interval already in the list: if the new one starts at or before the last one ends, they overlap, so merge them by extending the last interval's end to the larger of the two ends. Otherwise there's a gap, so just append the new interval to the list as its own entry. The sort dominates the runtime at O(n log n); the sweep is O(n).

Time
O(n log n)
Space
O(n)
Tap or swipe →
Walk-through
input:   [1,3], [2,6], [8,10], [15,18]
sorted:  [1,3], [2,6], [8,10], [15,18]   (already)

result = [[1,3]]

[2,6]:    2 ≤ 3  →  overlap, extend end to max(3,6) = 6
          result: [[1,6]]

[8,10]:   8 > 6  →  no overlap, push
          result: [[1,6], [8,10]]

[15,18]:  15 > 10  →  push
          result: [[1,6], [8,10], [15,18]] ✓
Tap or swipe → for solution
Solution · Java

Merge Intervals

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
37 / 75·IntervalMedium
Problem

Non-overlapping Intervals

Given intervals, return the minimum number you must remove so that the rest are non-overlapping. Greedy by earliest end time.

Input
intervals = [[1,2],[2,3],[3,4],[1,3]]
Output
1
Tap or swipe →LeetCode ↗
Approach
Greedy by earliest end time

Sort intervals by their END time. Walk through them, keeping track of the most recently kept interval's end. For each interval: if its start is >= the kept end, it doesn't overlap — keep it (update kept end). Otherwise it overlaps with what you've already kept; remove it (increment counter). Sorting by end time guarantees that whenever there's a conflict, removing the later-ending interval leaves the most room for everything that comes next — that's the greedy correctness argument.

Time
O(n log n)
Space
O(1)
Tap or swipe →
Walk-through
intervals = [[1,2], [2,3], [3,4], [1,3]]
sorted by end: [[1,2], [2,3], [1,3], [3,4]]

end = -∞, removed = 0

[1,2]: start 1 ≥ -∞, keep. end = 2
[2,3]: start 2 ≥ 2,  keep. end = 3
[1,3]: start 1 < 3,  remove. removed = 1
[3,4]: start 3 ≥ 3,  keep. end = 4

answer: 1
Tap or swipe → for solution
Solution · Java

Non-overlapping Intervals

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
38 / 75·IntervalEasy
Problem

Meeting Rooms

Given an array of meeting time intervals, determine if a person could attend all meetings (no overlaps).

Input
intervals = [[0,30],[5,10],[15,20]]
Output
false
Tap or swipe →LeetCode ↗
Approach
Sort + check adjacent overlap

Sort the meetings by start time. Then walk through and check every adjacent pair: if the current meeting starts before the previous one ends, you can't attend both — return false. If you reach the end without conflicts, you can attend them all.

Time
O(n log n)
Space
O(1)
Tap or swipe →
Walk-through
intervals = [[0,30], [5,10], [15,20]]
sorted:    [[0,30], [5,10], [15,20]]   (already)

i=1: starts 5  < prev end 30  → CONFLICT → return false
Tap or swipe → for solution
Solution · Java

Meeting Rooms

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
39 / 75·IntervalMedium
Problem

Meeting Rooms II

Given meeting intervals, return the minimum number of conference rooms needed. Use sorted starts/ends two-pointer or a min-heap of end times.

Input
intervals = [[0,30],[5,10],[15,20]]
Output
2
Tap or swipe →LeetCode ↗
Approach
Sweep-line with separate sorted starts/ends

Pull all start times into one sorted array and all end times into another. Walk a pointer s through the sorted starts. For each start time, ask 'has any meeting ended by now?' by comparing against ends[e]. If not, you need a new room (rooms++). If yes, an existing room frees up — advance the end pointer e instead. The peak number of overlapping meetings (the max value rooms reaches) is your answer.

Time
O(n log n)
Space
O(n)
Tap or swipe →
Walk-through
intervals = [[0,30], [5,10], [15,20]]

starts sorted: [0, 5, 15]
ends sorted:   [10, 20, 30]

s=0  starts[0]=0  < ends[0]=10  → rooms=1, s=1
s=1  starts[1]=5  < ends[0]=10  → rooms=2, s=2
s=2  starts[2]=15 ≥ ends[0]=10  → end frees up, e=1, s=3

answer: 2
Tap or swipe → for solution
Solution · Java

Meeting Rooms II

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
40 / 75·Linked ListEasy
Problem

Reverse Linked List

Given the head of a singly linked list, reverse the list and return the new head.

Input
1->2->3->4->5
Output
5->4->3->2->1
Tap or swipe →LeetCode ↗
Approach
Three-pointer iterative reversal

Walk the list once with three pointers. prev is the head of the reversed list you're building (starts as null). curr is the node you're currently flipping. next is a temporary that holds curr's original next pointer so you don't lose the rest of the original list when you overwrite it. At each step: save curr.next into next, set curr.next = prev (this is the actual reversal), then advance prev = curr and curr = next. When curr becomes null you've processed every node, and prev is the new head.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
start:  1 → 2 → 3 → 4 → null
        prev = null, curr = 1

step  next  reroute        prev   curr
 1     2    1 → null         1     2
 2     3    2 → 1            2     3
 3     4    3 → 2            3     4
 4    null  4 → 3            4    null

return prev (= 4)
result: 4 → 3 → 2 → 1 → null
Tap or swipe → for solution
Solution · Java

Reverse Linked List

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
41 / 75·Linked ListEasy
Problem

Linked List Cycle

Given head of a linked list, determine if it contains a cycle. Floyd's tortoise & hare: slow moves 1, fast moves 2; they meet inside any cycle.

Input
head = [3,2,0,-4], pos = 1
Output
true
Tap or swipe →LeetCode ↗
Approach
Floyd's tortoise and hare

Use two pointers: slow advances one node per step, fast advances two. If the list ends (fast reaches null), there's no cycle. If there IS a cycle, the fast pointer eventually 'laps' the slow one and they meet at some node inside the cycle — at that moment, return true. Constant extra space, no hash set needed.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
list with cycle:  1 → 2 → 3 → 4 → 5 → 2 (back to node 2)

step  slow  fast
 0     1     1
 1     2     3
 2     3     5
 3     4     3 (fast wrapped through 5→2→3)
 4     5     5  ← meet → return true
Tap or swipe → for solution
Solution · Java

Linked List Cycle

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
42 / 75·Linked ListEasy
Problem

Merge Two Sorted Lists

Merge two sorted linked lists and return as a single sorted list, splicing nodes (no new node creation needed).

Input
l1 = [1,2,4], l2 = [1,3,4]
Output
[1,1,2,3,4,4]
Tap or swipe →LeetCode ↗
Approach
Two-pointer splice with dummy head

Allocate a dummy head node so you don't need a special case for the very first node attached. Keep a tail pointer at dummy. Walk both lists with pointers a and b: at each step, splice whichever has the smaller value into tail.next, then advance that pointer and move tail forward. When one list runs out, attach the remainder of the other in one step. Return dummy.next.

Time
O(n + m)
Space
O(1)
Tap or swipe →
Walk-through
a = 1 → 2 → 4
b = 1 → 3 → 4

dummy → ?
tail = dummy

a.val=1, b.val=1. a ≤ b → tail.next=a, a=2, tail moves
a.val=2, b.val=1. a > b → tail.next=b, b=3, tail moves
a.val=2, b.val=3. a ≤ b → tail.next=a, a=4, tail moves
a.val=4, b.val=3. a > b → tail.next=b, b=4, tail moves
a.val=4, b.val=4. a ≤ b → tail.next=a, a=null, tail moves
b not null → tail.next = b (= 4)

result: 1 → 1 → 2 → 3 → 4 → 4
Tap or swipe → for solution
Solution · Java

Merge Two Sorted Lists

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
43 / 75·Linked ListHard
Problem

Merge K Sorted Lists

Given an array of k sorted linked lists, merge them into one sorted list. Pairwise merge (divide & conquer) is O(N log k).

Input
lists = [[1,4,5],[1,3,4],[2,6]]
Output
[1,1,2,3,4,4,5,6]
Tap or swipe →LeetCode ↗
Approach
Pairwise divide-and-conquer merging

Naively merging the lists one by one is O(N·k); we can do O(N log k) by merging in pairs and halving the list count each round. In each round, walk through the lists array merging i with i+1 (or with null if odd), producing half as many lists. Repeat until one list remains. The merge subroutine is just standard 'merge two sorted lists'. Each node is touched O(log k) times across all rounds.

Time
O(N log k) where N = total nodes
Space
O(1) extra (in-place splicing)
Tap or swipe →
Walk-through
lists = [L1, L2, L3, L4, L5]   (k = 5)

round 1: merge in pairs
  M1 = merge(L1, L2)
  M2 = merge(L3, L4)
  M3 = merge(L5, null) = L5
  lists = [M1, M2, M3]

round 2:
  N1 = merge(M1, M2)
  N2 = merge(M3, null) = M3
  lists = [N1, N2]

round 3:
  P1 = merge(N1, N2)
  lists = [P1]

return P1
Tap or swipe → for solution
Solution · Java

Merge K Sorted Lists

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
44 / 75·Linked ListMedium
Problem

Remove Nth Node From End

Given the head of a linked list, remove the nth node from the end and return the head. Use two pointers: advance fast n+1 steps first.

Input
head = [1,2,3,4,5], n = 2
Output
[1,2,3,5]
Tap or swipe →LeetCode ↗
Approach
Two pointers with n-step gap

Use a dummy node before head so removing the actual head isn't a special case. Set both fast and slow pointers at dummy. Advance fast by n + 1 steps. Then move both at the same pace until fast becomes null — at that moment slow sits exactly one node BEFORE the target. Splice it out with slow.next = slow.next.next, return dummy.next.

Time
O(L)
Space
O(1)
Tap or swipe →
Walk-through
list: 1 → 2 → 3 → 4 → 5,  n = 2  (remove 2nd-from-end = node 4)

dummy → 1 → 2 → 3 → 4 → 5 → null

advance fast n+1 = 3 steps from dummy:
  fast: dummy → 1 → 2 → 3

walk both at same pace until fast == null:
  slow=dummy, fast=3
  slow=1,     fast=4
  slow=2,     fast=5
  slow=3,     fast=null   (stop)

slow.next = node 4 → splice it out
  slow.next = slow.next.next   →   3.next becomes 5

result: 1 → 2 → 3 → 5
Tap or swipe → for solution
Solution · Java

Remove Nth Node From End

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
45 / 75·Linked ListMedium
Problem

Reorder List

Given L0->L1->...->Ln-1, reorder it to L0->Ln-1->L1->Ln-2->L2->Ln-3->... in place. Steps: find middle, reverse second half, weave the two halves.

Input
[1,2,3,4]
Output
[1,4,2,3]
Tap or swipe →LeetCode ↗
Approach
Find middle, reverse second half, weave

Three steps. (1) Find the middle of the list with slow/fast pointers — slow lands on the midpoint when fast hits the end. (2) Detach the second half and reverse it in place. (3) Weave the two halves together: take one node from the front, then one from the (now-reversed) back, alternating, until done. Each phase is O(n) and uses O(1) extra space.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
list: 1 → 2 → 3 → 4 → 5

step 1, find middle (slow/fast):  slow ends at 3
  split:  front = 1 → 2 → 3,  back = 4 → 5

step 2, reverse back:  5 → 4

step 3, weave:
  1.next = 5; 5.next = 2  →  1 → 5 → 2
  2.next = 4; 4.next = 3  →  1 → 5 → 2 → 4
  3 has no partner left

result: 1 → 5 → 2 → 4 → 3
Tap or swipe → for solution
Solution · Java

Reorder List

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
46 / 75·MatrixMedium
Problem

Set Matrix Zeroes

Given an m x n matrix, if a cell is 0, set its entire row and column to 0 — in place. Use the first row/col as markers; track them separately.

Input
matrix = [[1,1,1],[1,0,1],[1,1,1]]
Output
[[1,0,1],[0,0,0],[1,0,1]]
Tap or swipe →LeetCode ↗
Approach
Use first row/column as in-place markers

Naively you'd allocate two extra arrays (length m and n) to record which rows and columns to zero out. To do it in O(1) extra space, repurpose the matrix's own first row and first column as those markers. But first you have to remember separately whether the original first row and first column themselves contained any zeros (since you're about to overwrite them as markers). Then walk the rest of the matrix marking, then walk again zeroing based on the markers, and finally zero out the first row and column themselves if needed.

Time
O(m·n)
Space
O(1)
Tap or swipe →
Walk-through
matrix:
  1 1 1
  1 0 1   ← zero at (1,1)
  1 1 1

step 1: scan original first row and first column for zeros:
        firstRow = false, firstCol = false

step 2: scan inner cells; for any 0, mark its row and col in row 0 / col 0:
        (1,1)=0 → matrix[1][0] = 0, matrix[0][1] = 0

  1 0 1
  0 0 1
  1 1 1

step 3: zero inner cells whose row 0 or col 0 marker is 0:

  1 0 1
  0 0 0
  1 0 1

step 4: zero first row/col if their original flags were true (both false here)

result:
  1 0 1
  0 0 0
  1 0 1
Tap or swipe → for solution
Solution · Java

Set Matrix Zeroes

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
47 / 75·MatrixMedium
Problem

Spiral Matrix

Given an m x n matrix, return all elements in spiral order (right, down, left, up — repeat). Track top/bottom/left/right boundaries.

Input
matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output
[1,2,3,6,9,8,7,4,5]
Tap or swipe →LeetCode ↗
Approach
Four-direction boundary walk

Maintain four boundary variables: top, bottom, left, right. Repeatedly traverse one layer in four directions: left-to-right along the top row (then top++), top-to-bottom down the right column (then right--), right-to-left along the bottom row (then bottom--), and bottom-to-top up the left column (then left++). After each direction, shrink that boundary inward. Stop when the boundaries cross. Guard the bottom and left passes with extra checks for the case where they collapse to a single row or column.

Time
O(m·n)
Space
O(1) extra
Tap or swipe →
Walk-through
matrix:
  1  2  3
  4  5  6
  7  8  9

top=0, bot=2, left=0, right=2

right along top row 0:  1, 2, 3            top=1
down right col 2:       6, 9               right=1
left along bot row 2:   8, 7               bot=1
up left col 0:          4                  left=1

top=1, bot=1, left=1, right=1
right along top row 1:  5                  top=2
(other passes guarded — top > bot, stop)

answer: [1, 2, 3, 6, 9, 8, 7, 4, 5]
Tap or swipe → for solution
Solution · Java

Spiral Matrix

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
48 / 75·MatrixMedium
Problem

Rotate Image

Rotate an n x n matrix 90 degrees clockwise in place. Trick: transpose, then reverse each row.

Input
matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output
[[7,4,1],[8,5,2],[9,6,3]]
Tap or swipe →LeetCode ↗
Approach
Transpose + reverse rows

Rotating a square matrix 90° clockwise can be done with two simple in-place passes. Pass 1, transpose: swap matrix[i][j] with matrix[j][i] for every pair where i < j. This mirrors the matrix across its main diagonal (top-left to bottom-right). Pass 2, reverse each row left-to-right. The composition of those two operations is exactly a 90° clockwise rotation. Sketch it once on a 3×3 grid and the transformation becomes obvious; both passes are O(n²) time and O(1) extra space.

Time
O(n²)
Space
O(1)
Tap or swipe →
Walk-through
original          transpose          reverse each row
1 2 3             1 4 7              7 4 1
4 5 6     →       2 5 8       →      8 5 2
7 8 9             3 6 9              9 6 3

(transpose:                          (read each row
 swap matrix[i][j] ↔ matrix[j][i]    right-to-left)
 for all i < j)
Tap or swipe → for solution
Solution · Java

Rotate Image

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
49 / 75·MatrixMedium
Problem

Word Search

Given an m x n grid of letters and a word, return true if the word can be constructed from sequentially adjacent cells. The same cell may not be used twice.

Input
board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
Output
true
Tap or swipe →LeetCode ↗
Approach
DFS with backtracking

From each cell, try DFS searching for the word starting at index 0. At each step, check bounds, that the cell matches word[k], and that you haven't already used this cell on the current path. To avoid an extra visited array, temporarily overwrite the cell with a sentinel ('#') before recursing into the four neighbours, then restore it after the recursion returns — classic backtracking. If recursion ever succeeds (k reaches word.length), return true; otherwise undo the mark and let the next start cell try.

Time
O(m · n · 4^L) worst case
Space
O(L) recursion
Tap or swipe →
Walk-through
board:           word = "ABCCED"
  A B C E
  S F C S
  A D E E

start at (0,0)='A', match k=0.
  mark (0,0)='#', recurse looking for 'B'
  (0,1)='B' matches k=1. mark, recurse for 'C'
    (0,2)='C' matches k=2. mark, recurse for 'C'
      (1,2)='C' matches k=3. mark, recurse for 'E'
        (2,2)='E' matches k=4. mark, recurse for 'D'
          (2,1)='D' matches k=5. k+1 == word.length → return true ✓
Tap or swipe → for solution
Solution · Java

Word Search

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
50 / 75·StringMedium
Problem

Longest Substring Without Repeating Characters

Given a string s, find the length of the longest substring without repeating characters. Sliding window with a Map of last-seen indices.

Input
s = "abcabcbb"
Output
3
Tap or swipe →LeetCode ↗
Approach
Sliding window + last-seen map

Use a sliding window defined by two indices l (left edge) and r (right edge), both starting at 0. Also keep a hash map that remembers, for each character, the most recent index where you saw it. Move r forward one step at a time. When you encounter s[r], check the map: if you've seen this character at some position p that's still inside the window (p >= l), the window now contains a duplicate — slide l forward to p + 1 to kick the old occurrence out. Then update the map with s[r]'s new index, and update your best answer with the current window length r - l + 1. Each character is visited at most twice (once by r, once by l), so it's O(n).

Time
O(n)
Space
O(min(n, charset))
Tap or swipe →
Walk-through
s = "abcabcbb"
     0 1 2 3 4 5 6 7

r=0  'a' new          window [a]      len=1
r=1  'b' new          window [ab]     len=2
r=2  'c' new          window [abc]    len=3 ★ best
r=3  'a' last at 0    l → 1
                      window [bca]    len=3
r=4  'b' last at 1    l → 2
                      window [cab]    len=3
r=5  'c' last at 2    l → 3
                      window [abc]    len=3
r=6  'b' last at 4    l → 5
                      window [cb]     len=2
r=7  'b' last at 6    l → 7
                      window [b]      len=1

answer: 3
Tap or swipe → for solution
Solution · Java

Longest Substring Without Repeating Characters

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
51 / 75·StringMedium
Problem

Longest Repeating Character Replacement

Given string s and integer k, you may replace at most k characters with any letter. Return the length of the longest substring containing the same letter.

Input
s = "AABABBA", k = 1
Output
4
Tap or swipe →LeetCode ↗
Approach
Sliding window + count of dominant char

Slide a window [l, r] and within it count the frequency of every letter. Track maxCount — the highest frequency in the current window. The minimum number of characters you'd have to change to make the whole window one letter is windowSize - maxCount. If that exceeds k, the window is too big; shrink it by advancing l (and decrementing the leaving character's count). Otherwise it's valid — update your best length. You don't need to recompute maxCount after shrinking; only growing the window can ever beat the current best, and a stale max can't lead to wrong answers.

Time
O(n)
Space
O(1) — bounded alphabet
Tap or swipe →
Walk-through
s = "AABABBA", k = 1

count = [0]×26, l = 0, maxCount = 0, best = 0

r=0 'A': count[A]=1, maxCount=1.  win=1, 1-1=0 ≤ 1, best=1
r=1 'A': count[A]=2, maxCount=2.  win=2, 2-2=0 ≤ 1, best=2
r=2 'B': count[B]=1, max stays 2. win=3, 3-2=1 ≤ 1, best=3
r=3 'A': count[A]=3, maxCount=3.  win=4, 4-3=1 ≤ 1, best=4 ★
r=4 'B': count[B]=2, max stays 3. win=5, 5-3=2 > 1, shrink l→1 (A--)
                                    win=4, 4-3=1 ≤ 1, best=4
r=5 'B': count[B]=3, maxCount=3.  win=5, 5-3=2 > 1, shrink l→2 (A--)
                                    win=4, 4-3=1 ≤ 1, best=4
r=6 'A': count[A]=2 (stale max=3). win=5, 5-3=2 > 1, shrink l→3 (B--)
                                    win=4, 4-3=1 ≤ 1, best=4

answer: 4
Tap or swipe → for solution
Solution · Java

Longest Repeating Character Replacement

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
52 / 75·StringHard
Problem

Minimum Window Substring

Given strings s and t, return the minimum window substring of s such that every character in t (including counts) is included in the window. Sliding window + counts.

Input
s = "ADOBECODEBANC", t = "ABC"
Output
"BANC"
Tap or swipe →LeetCode ↗
Approach
Sliding window with required-character counts

Build a 'need' map of each character in t with its required count. Slide a window [l, r] over s and a 'window' map of counts inside it. Track 'have' = how many distinct characters have reached their required count. Expand r; whenever a character's window count hits its needed count, have++. Once have equals the number of distinct required chars, the window is feasible — try shrinking from the left to find the smallest such window, updating the best length each time. Keep shrinking until the window stops being feasible (some character drops below its need), then resume expanding r.

Time
O(|s| + |t|)
Space
O(|s| + |t|)
Tap or swipe →
Walk-through
s = "ADOBECODEBANC", t = "ABC"
need = {A:1, B:1, C:1}, required = 3

walk r forward, expanding the window:
  ... once r=5 the window covers "ADOBEC"
  A:1, B:1, C:1 all met → have=3

  shrink l:
    l=0 'A' leaves → A count drops to 0 < need → have=2
    best so far: "ADOBEC", len=6

continue r:
  ... eventually at r=12 the window covers "CODEBANC"
  shrink: window becomes "BANC" — A:1, B:1, C:1 still all met
  best updated: "BANC", len=4 ★

answer: "BANC"
Tap or swipe → for solution
Solution · Java

Minimum Window Substring

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
53 / 75·StringEasy
Problem

Valid Anagram

Given two strings s and t, return true if t is an anagram of s. Compare character counts.

Input
s = "anagram", t = "nagaram"
Output
true
Tap or swipe →LeetCode ↗
Approach
Single-array character count

If the lengths differ, they can't be anagrams. Otherwise walk both strings together with one int[26] array — increment for each char of s, decrement for each char of t at the same loop index. After the pass, if the two strings are anagrams, every counter ended up at zero. Any non-zero entry signals a mismatch.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
s = "anagram", t = "nagaram"

count = [0]×26
i=0  s='a' +1, t='n' -1   →  a:1, n:-1
i=1  s='n' +1, t='a' -1   →  a:0, n:0
i=2  s='a' +1, t='g' -1   →  a:1, g:-1
i=3  s='g' +1, t='a' -1   →  a:0, g:0
i=4  s='r' +1, t='r' -1   →  r:0
i=5  s='a' +1, t='a' -1   →  a:0
i=6  s='m' +1, t='m' -1   →  m:0

all zero → return true
Tap or swipe → for solution
Solution · Java

Valid Anagram

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
54 / 75·StringMedium
Problem

Group Anagrams

Given an array of strings, group the anagrams together. Use a sorted version of each string as the bucket key.

Input
strs = ["eat","tea","tan","ate","nat","bat"]
Output
[["eat","tea","ate"],["tan","nat"],["bat"]]
Tap or swipe →LeetCode ↗
Approach
Hash by sorted-letters key

Two strings are anagrams iff sorting their characters produces the same string. So use the sorted version of each string as a hash-map key and bucket the original strings under it. One pass: for each input, sort its characters, look up (or create) the bucket, append the original. Return all buckets. Sorting each string costs O(L log L); total is O(n · L log L) where L is the average length.

Time
O(n · L log L)
Space
O(n · L)
Tap or swipe →
Walk-through
strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

key       value
"aet"  →  ["eat", "tea", "ate"]
"ant"  →  ["tan", "nat"]
"abt"  →  ["bat"]

answer: [["eat","tea","ate"], ["tan","nat"], ["bat"]]
Tap or swipe → for solution
Solution · Java

Group Anagrams

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
55 / 75·StringEasy
Problem

Valid Parentheses

Given a string of '()[]{}', determine if the input has properly matched and nested brackets.

Input
s = "()[]{}"
Output
true
Tap or swipe →LeetCode ↗
Approach
Stack of expected closers

Use a stack. On every opening bracket, push it onto the stack. On every closing bracket, pop the top of the stack: if it doesn't match the expected opener for that closer (or the stack is empty), the string is invalid. After the whole pass, the stack must also be empty — leftover openers mean unclosed brackets.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
s = "()[]{}"

c='(' push          stack: [(]
c=')' pop '(' match stack: []
c='[' push          stack: [[]
c=']' pop '[' match stack: []
c='{' push          stack: [{]
c='}' pop '{' match stack: []

stack empty at end → valid
Tap or swipe → for solution
Solution · Java

Valid Parentheses

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
56 / 75·StringEasy
Problem

Valid Palindrome

Given a string s, return true if it is a palindrome considering only alphanumeric characters and ignoring case.

Input
s = "A man, a plan, a canal: Panama"
Output
true
Tap or swipe →LeetCode ↗
Approach
Two pointers, skip non-alphanumerics

Two pointers, l starting at 0 and r at the end. Advance each one inward, skipping any character that isn't a letter or digit. When both land on alphanumeric characters, compare them case-insensitively — if they differ, return false. Otherwise step both inward and repeat until they meet.

Time
O(n)
Space
O(1)
Tap or swipe →
Walk-through
s = "A man, a plan, a canal: Panama"

skip non-alnum, lowercase compare:
  l='a' vs r='a' ✓
  l='m' vs r='m' ✓
  l='a' vs r='a' ✓
  l='n' vs r='n' ✓
  l='a' vs r='a' ✓
  l='p' vs r='p' ✓
  ... eventually pointers meet in the middle

return true
Tap or swipe → for solution
Solution · Java

Valid Palindrome

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
57 / 75·StringMedium
Problem

Longest Palindromic Substring

Given a string s, return the longest palindromic substring. Expand around each center (odd and even).

Input
s = "babad"
Output
"bab" or "aba"
Tap or swipe →LeetCode ↗
Approach
Expand around each center

Every palindromic substring has a center. There are 2n - 1 candidate centers: n single characters (odd-length palindromes) and n - 1 pairs of adjacent characters (even-length palindromes). For each center, expand outward as long as the characters on both sides match — this finds the longest palindrome centered there in O(n). Track the best across all centers.

Time
O(n²)
Space
O(1)
Tap or swipe →
Walk-through
s = "babad"

center i=0 (odd):    "b" → length 1
center i=0/1 (even): "ba" no
center i=1 (odd):    "a" → expand "bab" length 3 ★
center i=1/2 (even): "ab" no
center i=2 (odd):    "b" → expand "aba" length 3
center i=2/3 (even): "ba" no
center i=3 (odd):    "a" → length 1
... etc.

answer: "bab" (or "aba")
Tap or swipe → for solution
Solution · Java

Longest Palindromic Substring

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
58 / 75·StringMedium
Problem

Palindromic Substrings

Given a string s, return the number of palindromic substrings in it. Expand around centers and count.

Input
s = "aaa"
Output
6
Tap or swipe →LeetCode ↗
Approach
Expand around each center, count

Same expand-around-center idea as Longest Palindromic Substring, but instead of tracking the longest, count every successful expansion. From each of the 2n - 1 candidate centers, every step outward where the two characters match adds one more palindrome to the count.

Time
O(n²)
Space
O(1)
Tap or swipe →
Walk-through
s = "aaa"

center 0:      "a"   → +1
center 0/1:    "aa"  → +1, expand fails
center 1:      "a"   → +1, then "aaa" → +1
center 1/2:    "aa"  → +1, expand fails
center 2:      "a"   → +1

total: 6
Tap or swipe → for solution
Solution · Java

Palindromic Substrings

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
59 / 75·StringMedium
Problem

Encode and Decode Strings

Design an algorithm to encode a list of strings to one string and decode it back. Length-prefix each string with a delimiter, e.g. '5#hello'.

Input
["lint","code","love","you"]
Output
"4#lint4#code4#love3#you"
Tap or swipe →LeetCode ↗
Approach
Length-prefix delimiter

Encode each string as 'length#string'. The length tells the decoder exactly how many characters to read for that string — so the strings themselves can contain any character, including '#', without ambiguity. Decoding: scan forward to find the next '#', parse the number before it as the length, then take exactly that many characters as the next string. Repeat until you've consumed the input.

Time
O(N) where N = total characters
Space
O(N)
Tap or swipe →
Walk-through
encode(["lint", "code", "love", "you"])
  = "4#lint" + "4#code" + "4#love" + "3#you"
  = "4#lint4#code4#love3#you"

decode:
  i=0  scan to '#' at 1, len=4. take s[2..6]="lint",  i=6
  i=6  scan to '#' at 7, len=4. take s[8..12]="code", i=12
  i=12 scan to '#' at 13, len=4. take s[14..18]="love", i=18
  i=18 scan to '#' at 19, len=3. take s[20..23]="you", i=23

answer: ["lint", "code", "love", "you"]
Tap or swipe → for solution
Solution · Java

Encode and Decode Strings

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
60 / 75·TreeEasy
Problem

Maximum Depth of Binary Tree

Given the root of a binary tree, return its maximum depth.

Input
root = [3,9,20,null,null,15,7]
Output
3
Tap or swipe →LeetCode ↗
Approach
Recursive DFS

An empty tree has depth 0. Otherwise the depth of the tree rooted at this node is 1 (for itself) plus the maximum depth of its two subtrees. That's the entire algorithm — the recursion does the work.

Time
O(n)
Space
O(h) recursion stack
Tap or swipe →
Walk-through
       3
      / \
     9  20
        / \
       15  7

depth(3) = 1 + max(depth(9), depth(20))
  depth(9)  = 1 + max(0, 0) = 1
  depth(20) = 1 + max(depth(15), depth(7)) = 1 + max(1, 1) = 2

depth(3) = 1 + max(1, 2) = 3
Tap or swipe → for solution
Solution · Java

Maximum Depth of Binary Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
61 / 75·TreeEasy
Problem

Same Tree

Given the roots of two binary trees p and q, return true if they are structurally identical and the nodes have the same values.

Input
p = [1,2,3], q = [1,2,3]
Output
true
Tap or swipe →LeetCode ↗
Approach
Parallel recursion

Two trees are the same iff: both are null (base case true), OR both are non-null AND have the same value AND their left subtrees are the same AND their right subtrees are the same. Recurse on both pairs simultaneously.

Time
O(n)
Space
O(h) recursion stack
Tap or swipe →
Walk-through
p:       q:
  1        1
 / \      / \
2   3    2   3

isSame(p, q):
  both non-null, vals 1 == 1
  isSame(p.left, q.left):  both vals 2 ✓
  isSame(p.right, q.right): both vals 3 ✓
  → return true
Tap or swipe → for solution
Solution · Java

Same Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
62 / 75·TreeEasy
Problem

Invert Binary Tree

Given the root of a binary tree, invert the tree (mirror it) and return its root.

Input
[4,2,7,1,3,6,9]
Output
[4,7,2,9,6,3,1]
Tap or swipe →LeetCode ↗
Approach
Post-order swap

Recursively invert the left and right subtrees first, then swap them at the current node. This effectively mirrors the entire tree across its vertical axis. Equivalently: just swap children at every node — the order doesn't matter as long as each node ends up with its children flipped.

Time
O(n)
Space
O(h) recursion stack
Tap or swipe →
Walk-through
input:           output:
     4               4
    / \             / \
   2   7           7   2
  / \ / \         / \ / \
 1  3 6  9       9  6 3  1

at root 4: swap children
  left subtree (recursively inverted) becomes new right
  right subtree (recursively inverted) becomes new left
Tap or swipe → for solution
Solution · Java

Invert Binary Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
63 / 75·TreeHard
Problem

Binary Tree Maximum Path Sum

A path is any sequence of nodes connected by edges. Return the maximum sum of any non-empty path. Track best at each node; return 'gain' upward.

Input
root = [-10,9,20,null,null,15,7]
Output
42
Tap or swipe →LeetCode ↗
Approach
DFS returning best one-side gain, tracking global best

Two values matter at each node. (a) The best path sum that PASSES THROUGH this node and uses BOTH children — this might be the global answer, but it can't propagate upward, since a path can only enter a parent from one side. (b) The best path sum a parent can extend through this node — uses at most ONE child (whichever has the larger gain). Recurse to get both children's gainable sums, clamp negatives to 0 (a negative gain is worse than not extending), update the global best with node.val + leftGain + rightGain, and return node.val + max(leftGain, rightGain) for the parent to consume.

Time
O(n)
Space
O(h)
Tap or swipe →
Walk-through
       -10
       / \
      9  20
         / \
        15  7

dfs(15) → return 15. best = max(best, 15) = 15
dfs(7)  → return 7.  best = max(best, 7)  = 15
dfs(20) → l=15, r=7
          best = max(best, 20+15+7=42) = 42 ★
          return 20 + max(15, 7) = 35
dfs(9)  → return 9. best = max(best, 9) = 42
dfs(-10)→ l=9, r=35
          best = max(best, -10+9+35=34) = 42
          return -10 + max(9, 35) = 25

answer: 42  (path 15 → 20 → 7)
Tap or swipe → for solution
Solution · Java

Binary Tree Maximum Path Sum

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
64 / 75·TreeMedium
Problem

Binary Tree Level Order Traversal

Given the root of a binary tree, return the level order traversal of its nodes' values (BFS).

Input
root = [3,9,20,null,null,15,7]
Output
[[3],[9,20],[15,7]]
Tap or swipe →LeetCode ↗
Approach
BFS by level

Standard BFS with a queue, but to know where each level ends, snapshot the queue size at the start of every level — that's exactly the count of nodes belonging to this level. Pop exactly that many, collect their values into one list, and enqueue all their children for the next level. Repeat until the queue is empty.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
       3
      / \
     9  20
        / \
       15  7

queue=[3]                    →  level: [3]      enqueue 9, 20
queue=[9, 20]                →  level: [9, 20]  enqueue 15, 7
queue=[15, 7]                →  level: [15, 7]
queue=[]

answer: [[3], [9, 20], [15, 7]]
Tap or swipe → for solution
Solution · Java

Binary Tree Level Order Traversal

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
65 / 75·TreeHard
Problem

Serialize and Deserialize Binary Tree

Design an algorithm to serialize a binary tree to a string and deserialize it back. Preorder DFS with '#' for null works well.

Input
root = [1,2,3,null,null,4,5]
Output
"1,2,#,#,3,4,#,#,5,#,#"
Tap or swipe →LeetCode ↗
Approach
Preorder DFS with null markers

Serialize via preorder DFS, emitting each node's value (and a sentinel like '#' for nulls) separated by commas. The null markers are crucial — they tell the deserializer where each subtree ends. Deserialize by tokenising the string and recursively rebuilding: read the next token; if it's '#' return null, otherwise create a node and recurse to fill in its left then right children.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
tree:         1
             / \
            2   3
               / \
              4   5

serialize (preorder):  "1,2,#,#,3,4,#,#,5,#,#"

deserialize, tokens: [1,2,#,#,3,4,#,#,5,#,#]
  build(): take 1 → node(1)
    left = build(): take 2 → node(2)
      left = build(): take #  → null
      right = build(): take # → null
    right = build(): take 3 → node(3)
      left  = build(): take 4 → node(4) with two null kids
      right = build(): take 5 → node(5) with two null kids

reconstructed identical tree
Tap or swipe → for solution
Solution · Java

Serialize and Deserialize Binary Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
66 / 75·TreeEasy
Problem

Subtree of Another Tree

Given roots root and subRoot, return true if subRoot has the same structure & values as some subtree of root.

Input
root = [3,4,5,1,2], subRoot = [4,1,2]
Output
true
Tap or swipe →LeetCode ↗
Approach
DFS + same-tree check at each node

At every node of the main tree, ask 'is this node the root of a subtree identical to subRoot?' using a standard same-tree comparison. If yes, return true. Otherwise recurse into the left and right children. The same-tree check is O(size of sub) and you do it at each of the O(n) main nodes — O(n · m) overall.

Time
O(n · m)
Space
O(h)
Tap or swipe →
Walk-through
root:          sub:
     3              4
    / \            / \
   4   5          1   2
  / \
 1   2

isSubtree(3, sub):
  same(3, sub)?  3 != 4, no
  recurse left = isSubtree(4, sub):
    same(4, sub)? structures and values match → return true
return true
Tap or swipe → for solution
Solution · Java

Subtree of Another Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
67 / 75·TreeMedium
Problem

Construct Tree from Preorder & Inorder

Given preorder and inorder traversals of a binary tree (with unique values), reconstruct and return the tree. preorder[0] is the root; locate it in inorder to split left/right.

Input
preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output
[3,9,20,null,null,15,7]
Tap or swipe →LeetCode ↗
Approach
Recursive split using inorder index map

Preorder visits the root before its subtrees, so preorder[0] is the root. In inorder, the root's position splits the array into the left subtree (everything before) and the right subtree (everything after). Recurse: build the left subtree from the left part of inorder, advancing through preorder; then build the right subtree from the right part. Pre-build a HashMap of value → inorderIndex so each split is O(1) instead of O(n) — that drops total time from O(n²) to O(n).

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
preorder = [3, 9, 20, 15, 7]
inorder  = [9, 3, 15, 20, 7]

idxMap: 9→0, 3→1, 15→2, 20→3, 7→4

build(0, 4): preorder[p=0]=3 → root(3); inorder split at index 1
  left = build(0, 0): preorder[p=1]=9 → leaf 9
  right = build(2, 4): preorder[p=2]=20 → root(20); split at 3
    left = build(2, 2): preorder[p=3]=15 → leaf 15
    right = build(4, 4): preorder[p=4]=7 → leaf 7

reconstructed tree matches.
Tap or swipe → for solution
Solution · Java

Construct Tree from Preorder & Inorder

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
68 / 75·TreeMedium
Problem

Validate Binary Search Tree

Given the root of a binary tree, determine if it is a valid BST. Pass an open (lo, hi) range down recursively.

Input
root = [2,1,3]
Output
true
Tap or swipe →LeetCode ↗
Approach
Range propagation (DFS)

The naive check — 'for each node, is its left child smaller and right child larger?' — is wrong, because a node deep in the left subtree can still be larger than an ancestor higher up and the local check would miss it. The correct approach is to track an open range (lo, hi) that every node's value must fall strictly inside. Start the recursion at the root with the range (-∞, +∞). When you recurse into the left child, the new range is (lo, node.val) — the left subtree must be smaller than the current node. When you recurse right, it's (node.val, hi). If any node ever falls outside its inherited range, the tree is not a valid BST.

Time
O(n)
Space
O(h) recursion
Tap or swipe →
Walk-through
valid example:

        5            range (-∞, +∞)  ✓
       / \
      3   7         (-∞, 5) ✓   (5, +∞) ✓
     / \   \
    1   4   8       1 ∈ (-∞, 3) ✓
                    4 ∈ (3, 5)  ✓
                    8 ∈ (7, +∞) ✓

counter-example (why local checks fail):

        5
       / \
      3   7
         / \
        4   8       4 ∈ (5, 7)?  NO — 4 ≤ 5 → INVALID

(child-only check sees 4 < 7 and incorrectly passes)
Tap or swipe → for solution
Solution · Java

Validate Binary Search Tree

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
69 / 75·TreeMedium
Problem

Kth Smallest Element in a BST

Given the root of a BST and an integer k, return the kth smallest value (1-indexed). Iterative inorder traversal.

Input
root = [3,1,4,null,2], k = 1
Output
1
Tap or swipe →LeetCode ↗
Approach
Iterative inorder traversal with early stop

An inorder traversal of a BST visits values in sorted order, so the kth value visited is the answer. Do it iteratively with an explicit stack: walk left as far as possible, pushing nodes; then pop the top, decrement k, and if k hits zero return that node's value; otherwise move into its right subtree and continue. Stops as soon as you've found it — average case faster than visiting all nodes.

Time
O(h + k)
Space
O(h)
Tap or swipe →
Walk-through
      3
     / \
    1   4
     \
      2

stack = [], curr = 3, k = 2

push 3, curr = 1
push 1, curr = null
pop 1, --k = 1.   not 0.   curr = 1.right = 2
push 2, curr = null
pop 2, --k = 0.   return 2 ✓
Tap or swipe → for solution
Solution · Java

Kth Smallest Element in a BST

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
70 / 75·TreeMedium
Problem

Lowest Common Ancestor of BST

Given a BST and two nodes p and q, return their lowest common ancestor. Walk down: when p and q split, that node is the LCA.

Input
root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output
6
Tap or swipe →LeetCode ↗
Approach
BST-property descent

Walk down from the root. At each node, compare its value to both p.val and q.val. If both targets are smaller, the LCA is in the left subtree — descend left. If both are larger, descend right. The first time the values 'split' (one ≤ this node and the other ≥, or one equals it), this node IS the LCA — return it. O(h) without any extra space.

Time
O(h)
Space
O(1)
Tap or swipe →
Walk-through
       6
      / \
     2   8
    / \ / \
   0  4 7  9
      / \
     3   5

p = 2, q = 8

at root 6: p.val=2 < 6, q.val=8 > 6 → split here, return 6

answer: 6
Tap or swipe → for solution
Solution · Java

Lowest Common Ancestor of BST

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
71 / 75·TreeMedium
Problem

Implement Trie (Prefix Tree)

Implement a Trie with insert(word), search(word), and startsWith(prefix) operations.

Input
insert("apple"), search("apple"), search("app"), startsWith("app")
Output
true, false, true
Tap or swipe →LeetCode ↗
Approach
26-ary tree with end-of-word flag

Each node has up to 26 children (one per lowercase letter) and a boolean 'end' flag. insert: walk character by character, creating missing children as you go; mark the final node as end. search: walk through; if any expected child is missing return false; at the end, return whether the final node has end == true. startsWith is the same walk but it ignores the end flag — just needing the path to exist is enough. All operations are O(L) where L is the word/prefix length.

Time
insert/search/startsWith O(L)
Space
O(total chars across all words)
Tap or swipe →
Walk-through
insert("apple"):
  root → a → p → p → l → e (mark end)

insert("app"):
  walk root → a → p → p (already exist), mark this 'p' as end

search("apple"):    walk a → p → p → l → e, end=true → true
search("app"):      walk a → p → p,         end=true → true
search("appl"):     walk a → p → p → l,     end=false → false
startsWith("app"):  walk a → p → p exists → true
Tap or swipe → for solution
Solution · Java

Implement Trie (Prefix Tree)

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
72 / 75·TreeMedium
Problem

Add and Search Word

Design WordDictionary supporting addWord and search where '.' matches any letter. DFS over a Trie when '.' is encountered.

Input
add "bad","dad","mad", search "pad","bad",".ad","b.."
Output
false, true, true, true
Tap or swipe →LeetCode ↗
Approach
Trie + DFS for wildcards

Same Trie structure as the basic Implement Trie. addWord is identical. The twist is search: when the search character is '.', it matches any letter, so you have to try EVERY existing child at that node and recurse — return true if any branch succeeds. For a normal letter, just descend that one branch as usual. The wildcard branching is what forces a recursive (DFS) search instead of a simple walk.

Time
addWord O(L); search O(L) for plain words, up to O(26^d · L) for d wildcards
Space
O(total chars)
Tap or swipe →
Walk-through
add "bad", "dad", "mad" → trie has three branches under root: b, d, m

search(".ad"):
  at root, '.' → try every child
    branch b: search "ad" → b → a → d, end=true → true ✓
return true

search("b.."):
  at root, 'b' → only branch b
  in b: '.' → try every child (only 'a')
    in a: '.' → try every child (only 'd')
      in d: end=true → true ✓
return true
Tap or swipe → for solution
Solution · Java

Add and Search Word

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
73 / 75·TreeHard
Problem

Word Search II

Given a board of letters and a list of words, return all words that can be formed in the board. Build a Trie of the words and DFS once.

Input
board, words = ["oath","pea","eat","rain"]
Output
["eat","oath"]
Tap or swipe →LeetCode ↗
Approach
Trie of words + grid DFS

Naively running Word Search once per query word is O(words × m·n·4^L). Build a Trie containing all the words, then DFS once from each cell, walking the Trie in lockstep — at each step, the current Trie node tells you which letters are even worth trying next. When you reach a Trie node that marks the end of a word, record it (and clear the marker so the same word isn't recorded twice). Standard backtracking on the board: replace the current cell with '#' before recursing, restore it after.

Time
O(m · n · 4^L)
Space
O(total chars in words)
Tap or swipe →
Walk-through
board:                  words = ["oath", "pea", "eat", "rain"]
  o a a n
  e t a e
  i h k r
  i f l v

build trie of all four words.

dfs from each cell:
  start (0,0)='o': trie has 'o' branch → enter, mark cell '#'
    move to (1,0)='e': no 'e' under o. backtrack.
    move to (0,1)='a': trie has 'a' under o → enter
      move to (1,1)='t': trie has 't' under oa → enter
        move to (2,1)='h': trie has 'h' under oat AND end-of-word "oath"
          → add "oath" to result, clear marker
  ... similar walk eventually finds "eat"

answer: ["oath", "eat"]
Tap or swipe → for solution
Solution · Java

Word Search II

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
74 / 75·HeapMedium
Problem

Top K Frequent Elements

Given nums and integer k, return the k most frequent elements. Bucket sort by frequency for O(n).

Input
nums = [1,1,1,2,2,3], k = 2
Output
[1,2]
Tap or swipe →LeetCode ↗
Approach
Bucket sort by frequency

First, count how many times each number appears using a hash map. The key observation: any frequency must be between 1 and n (the array length). So allocate n + 1 buckets, where bucket[f] holds every value that appears exactly f times. Walk those buckets from the highest index downward and pull values into your answer until you have k of them. This avoids both sorting (O(n log n)) and a heap (O(n log k)), giving you a flat O(n) algorithm because the bucket index IS the frequency — no comparisons needed.

Time
O(n)
Space
O(n)
Tap or swipe →
Walk-through
nums = [1,1,1,2,2,3], k = 2

count:   1→3,  2→2,  3→1

buckets (index = frequency):
  [0] → []
  [1] → [3]      (3 appears once)
  [2] → [2]      (2 appears twice)
  [3] → [1]      (1 appears three times)

walk from highest frequency:
  bucket[3]: take 1   →  result = [1]
  bucket[2]: take 2   →  result = [1, 2]   ✓ have k

answer: [1, 2]
Tap or swipe → for solution
Solution · Java

Top K Frequent Elements

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗
75 / 75·HeapHard
Problem

Find Median from Data Stream

Design MedianFinder with addNum(num) and findMedian(). Maintain a max-heap (lower half) and min-heap (upper half), kept balanced.

Input
addNum(1), addNum(2), findMedian(), addNum(3), findMedian()
Output
1.5, 2
Tap or swipe →LeetCode ↗
Approach
Two heaps split at the median

Maintain two heaps balanced at the median: a max-heap (lo) holding the smaller half of the numbers, and a min-heap (hi) holding the larger half. Invariant: lo's size is always either equal to hi's size or one greater. To addNum: push into lo, then move lo's max into hi (this guarantees lo's max ≤ hi's min); rebalance by moving one back if hi got bigger than lo. To findMedian: if lo has more elements, the median is lo's max; otherwise it's the average of lo's max and hi's min. Each insert is O(log n); the median query is O(1).

Time
addNum O(log n), findMedian O(1)
Space
O(n)
Tap or swipe →
Walk-through
addNum(1)
  push 1 into lo. shuttle to hi. lo smaller → rebalance back.
  lo = [1], hi = []

addNum(2)
  push 2 into lo. shuttle 2 to hi. balanced, no rebalance.
  lo = [1], hi = [2]

findMedian()
  sizes equal → (1 + 2) / 2 = 1.5

addNum(3)
  push 3 into lo (lo top is 3). shuttle 3 to hi (hi has 2, 3).
  hi.size > lo.size → shuttle hi.min=2 back to lo.
  lo = [1, 2], hi = [3]

findMedian()
  lo bigger → return lo.max = 2
Tap or swipe → for solution
Solution · Java

Find Median from Data Stream

Active recall

Try it first

Sketch the solution mentally — or actually code it on LeetCode. Then reveal and rate yourself honestly.

Swipe ↑ for next problemLeetCode ↗