Skip to content

Getting Started Problem Set

This is the first stop on the problem-set track: a warm-up mix that touches most of the core patterns from earlier phases without leaning too hard on any single one. If you can clear these eight, you’re ready for the sharper Arrays and Strings and Trees and Graphs sets that follow.

What you’ll learn

  • How to turn a pattern you already know (hash maps, two pointers, Kadane’s algorithm, linked-list rewiring) into working code under light pressure.
  • How to read a stub, find the # TODO# TODO, and make the printed output match the # expect# expect comment.
  • That “press Run, see it fail, fix one line, press Run again” is a normal and fast loop — not a sign you’re stuck.

How to use this set

Each problem below has three parts:

  1. A problem statement with the constraints that matter.
  2. A runnable stub — a function with a # TODO# TODO and some print(...)print(...) calls under a # Sample tests# Sample tests comment. Press Run on the code block to execute it right here in the browser.
  3. A collapsed Show solution — a complete, annotated answer with its time/space complexity. Open it only after you’ve genuinely tried.

Problems

1. Two Sum — LC 1 — Easy

Open LC 1 on LeetCode

Pattern: Hash Map — see Hash Tables.

Problem. Given an array of integers numsnums and an integer targettarget, return the indices of the two numbers that add up to targettarget. Assume exactly one valid answer exists, and you may not use the same element twice. 2 <= len(nums) <= 10^42 <= len(nums) <= 10^4.

two_sum.py
def two_sum(nums, target):
    # TODO: return indices of the two numbers adding to target
    pass
 
 
# Sample tests (press Run):
print(two_sum([2, 7, 11, 15], 9))   # expect [0, 1]
print(two_sum([3, 2, 4], 6))        # expect [1, 2]
print(two_sum([3, 3], 6))           # expect [0, 1]
two_sum.py
def two_sum(nums, target):
    # TODO: return indices of the two numbers adding to target
    pass
 
 
# Sample tests (press Run):
print(two_sum([2, 7, 11, 15], 9))   # expect [0, 1]
print(two_sum([3, 2, 4], 6))        # expect [1, 2]
print(two_sum([3, 3], 6))           # expect [0, 1]
Show solution
python
def two_sum(nums, target):
    seen = {}                       # value -> index seen so far
    for i, n in enumerate(nums):
        complement = target - n
        if complement in seen:
            return [seen[complement], i]
        seen[n] = i
    return []
 
 
print(two_sum([2, 7, 11, 15], 9))   # [0, 1]
print(two_sum([3, 2, 4], 6))        # [1, 2]
print(two_sum([3, 3], 6))           # [0, 1]
python
def two_sum(nums, target):
    seen = {}                       # value -> index seen so far
    for i, n in enumerate(nums):
        complement = target - n
        if complement in seen:
            return [seen[complement], i]
        seen[n] = i
    return []
 
 
print(two_sum([2, 7, 11, 15], 9))   # [0, 1]
print(two_sum([3, 2, 4], 6))        # [1, 2]
print(two_sum([3, 3], 6))           # [0, 1]

One pass, one hash map: for every number, check whether its complement was already seen before inserting the current number. Time: O(n)O(n). Space: O(n)O(n).

2. Valid Palindrome — LC 125 — Easy

Open LC 125 on LeetCode

Pattern: Two Pointers — see Two Pointers.

Problem. Given a string ss, return TrueTrue if it reads the same forwards and backwards after converting to lowercase and removing every character that isn’t alphanumeric.

valid_palindrome.py
def is_palindrome(s):
    # TODO: return True if s is a palindrome, ignoring case and non-alphanumerics
    pass
 
 
# Sample tests (press Run):
print(is_palindrome("A man, a plan, a canal: Panama"))   # expect True
print(is_palindrome("race a car"))                        # expect False
print(is_palindrome(" "))                                  # expect True
valid_palindrome.py
def is_palindrome(s):
    # TODO: return True if s is a palindrome, ignoring case and non-alphanumerics
    pass
 
 
# Sample tests (press Run):
print(is_palindrome("A man, a plan, a canal: Panama"))   # expect True
print(is_palindrome("race a car"))                        # expect False
print(is_palindrome(" "))                                  # expect True
Show solution
python
def is_palindrome(s):
    cleaned = [c.lower() for c in s if c.isalnum()]
    left, right = 0, len(cleaned) - 1
    while left < right:
        if cleaned[left] != cleaned[right]:
            return False
        left += 1
        right -= 1
    return True
 
 
print(is_palindrome("A man, a plan, a canal: Panama"))   # True
print(is_palindrome("race a car"))                        # False
print(is_palindrome(" "))                                  # True
python
def is_palindrome(s):
    cleaned = [c.lower() for c in s if c.isalnum()]
    left, right = 0, len(cleaned) - 1
    while left < right:
        if cleaned[left] != cleaned[right]:
            return False
        left += 1
        right -= 1
    return True
 
 
print(is_palindrome("A man, a plan, a canal: Panama"))   # True
print(is_palindrome("race a car"))                        # False
print(is_palindrome(" "))                                  # True

Clean once, then close in from both ends — the moment two characters disagree, it can’t be a palindrome. Time: O(n)O(n). Space: O(n)O(n) for the cleaned copy (can be made O(1)O(1) by indexing into ss directly and skipping non-alphanumeric characters as you go).

3. Best Time to Buy and Sell Stock — LC 121 — Easy

Open LC 121 on LeetCode

Pattern: One-pass / greedy scan (same-direction pointer) — see Two Pointers.

Problem. Given an array pricesprices where prices[i]prices[i] is the price of a stock on day ii, choose a single day to buy and a later day to sell to maximize profit. Return the maximum profit, or 00 if no profit is possible.

max_profit.py
def max_profit(prices):
    # TODO: return the max profit from one buy and one later sell
    pass
 
 
# Sample tests (press Run):
print(max_profit([7, 1, 5, 3, 6, 4]))   # expect 5
print(max_profit([7, 6, 4, 3, 1]))      # expect 0
max_profit.py
def max_profit(prices):
    # TODO: return the max profit from one buy and one later sell
    pass
 
 
# Sample tests (press Run):
print(max_profit([7, 1, 5, 3, 6, 4]))   # expect 5
print(max_profit([7, 6, 4, 3, 1]))      # expect 0
Show solution
python
def max_profit(prices):
    min_price = float("inf")
    best = 0
    for price in prices:
        min_price = min(min_price, price)
        best = max(best, price - min_price)
    return best
 
 
print(max_profit([7, 1, 5, 3, 6, 4]))   # 5
print(max_profit([7, 6, 4, 3, 1]))      # 0
python
def max_profit(prices):
    min_price = float("inf")
    best = 0
    for price in prices:
        min_price = min(min_price, price)
        best = max(best, price - min_price)
    return best
 
 
print(max_profit([7, 1, 5, 3, 6, 4]))   # 5
print(max_profit([7, 6, 4, 3, 1]))      # 0

Track the lowest price seen so far as you scan left to right; at every day, ask “what if I sold today?” and keep the best of those answers. Time: O(n)O(n). Space: O(1)O(1).

4. Contains Duplicate — LC 217 — Easy

Open LC 217 on LeetCode

Pattern: Hash Set — see Hash Tables.

Problem. Given an integer array numsnums, return TrueTrue if any value appears at least twice, and FalseFalse if every element is distinct.

contains_duplicate.py
def contains_duplicate(nums):
    # TODO: return True if any value appears more than once
    pass
 
 
# Sample tests (press Run):
print(contains_duplicate([1, 2, 3, 1]))   # expect True
print(contains_duplicate([1, 2, 3, 4]))   # expect False
contains_duplicate.py
def contains_duplicate(nums):
    # TODO: return True if any value appears more than once
    pass
 
 
# Sample tests (press Run):
print(contains_duplicate([1, 2, 3, 1]))   # expect True
print(contains_duplicate([1, 2, 3, 4]))   # expect False
Show solution
python
def contains_duplicate(nums):
    seen = set()
    for n in nums:
        if n in seen:
            return True
        seen.add(n)
    return False
 
 
print(contains_duplicate([1, 2, 3, 1]))   # True
print(contains_duplicate([1, 2, 3, 4]))   # False
python
def contains_duplicate(nums):
    seen = set()
    for n in nums:
        if n in seen:
            return True
        seen.add(n)
    return False
 
 
print(contains_duplicate([1, 2, 3, 1]))   # True
print(contains_duplicate([1, 2, 3, 4]))   # False

A set gives O(1)O(1) average membership checks, so one linear pass is enough. Time: O(n)O(n). Space: O(n)O(n).

5. Valid Anagram — LC 242 — Easy

Open LC 242 on LeetCode

Pattern: Hash Map (character counting) — see Hash Tables.

Problem. Given two strings ss and tt, return TrueTrue if tt is an anagram of ss (same characters, same multiplicity, any order).

valid_anagram.py
def is_anagram(s, t):
    # TODO: return True if t is an anagram of s
    pass
 
 
# Sample tests (press Run):
print(is_anagram("anagram", "nagaram"))   # expect True
print(is_anagram("rat", "car"))           # expect False
valid_anagram.py
def is_anagram(s, t):
    # TODO: return True if t is an anagram of s
    pass
 
 
# Sample tests (press Run):
print(is_anagram("anagram", "nagaram"))   # expect True
print(is_anagram("rat", "car"))           # expect False
Show solution
python
from collections import Counter
 
 
def is_anagram(s, t):
    if len(s) != len(t):
        return False
    return Counter(s) == Counter(t)
 
 
print(is_anagram("anagram", "nagaram"))   # True
print(is_anagram("rat", "car"))           # False
python
from collections import Counter
 
 
def is_anagram(s, t):
    if len(s) != len(t):
        return False
    return Counter(s) == Counter(t)
 
 
print(is_anagram("anagram", "nagaram"))   # True
print(is_anagram("rat", "car"))           # False

Two strings are anagrams exactly when their character-frequency maps are equal — CounterCounter builds that map for you. Time: O(n)O(n). Space: O(1)O(1) (bounded alphabet) or O(n)O(n) for a general Unicode alphabet.

6. Maximum Subarray (Kadane) — LC 53 — Medium

Open LC 53 on LeetCode

Pattern: 1-D Dynamic Programming — see One Dimensional DP.

Problem. Given an integer array numsnums, find the contiguous subarray with the largest sum and return that sum. The array has at least one element.

max_subarray.py
def max_subarray(nums):
    # TODO: return the largest sum of any contiguous subarray
    pass
 
 
# Sample tests (press Run):
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))   # expect 6
print(max_subarray([1]))                                # expect 1
print(max_subarray([5, 4, -1, 7, 8]))                   # expect 23
max_subarray.py
def max_subarray(nums):
    # TODO: return the largest sum of any contiguous subarray
    pass
 
 
# Sample tests (press Run):
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))   # expect 6
print(max_subarray([1]))                                # expect 1
print(max_subarray([5, 4, -1, 7, 8]))                   # expect 23
Show solution
python
def max_subarray(nums):
    best = nums[0]
    current = nums[0]
    for n in nums[1:]:
        current = max(n, current + n)   # extend the run, or start fresh at n
        best = max(best, current)
    return best
 
 
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))   # 6
print(max_subarray([1]))                                # 1
print(max_subarray([5, 4, -1, 7, 8]))                   # 23
python
def max_subarray(nums):
    best = nums[0]
    current = nums[0]
    for n in nums[1:]:
        current = max(n, current + n)   # extend the run, or start fresh at n
        best = max(best, current)
    return best
 
 
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))   # 6
print(max_subarray([1]))                                # 1
print(max_subarray([5, 4, -1, 7, 8]))                   # 23

Kadane’s algorithm is a 1-D DP in disguise: currentcurrent is “best sum of a subarray ending exactly here.” At each step it’s either worth extending or worth abandoning and restarting at the current element. Time: O(n)O(n). Space: O(1)O(1).

7. Fizz Buzz — LC 412 — Easy

Open LC 412 on LeetCode

Pattern: Simulation / modulo arithmetic (no dedicated pattern page — this one is about clean conditionals, not a named technique).

Problem. Given an integer nn, return a list of strings for the numbers 11 to nn where: multiples of 3 become "Fizz""Fizz", multiples of 5 become "Buzz""Buzz", multiples of both become "FizzBuzz""FizzBuzz", and everything else is the number itself as a string.

fizz_buzz.py
def fizz_buzz(n):
    # TODO: return list of strings 1..n applying the Fizz/Buzz/FizzBuzz rules
    pass
 
 
# Sample tests (press Run):
print(fizz_buzz(5))         # expect ['1', '2', 'Fizz', '4', 'Buzz']
print(repr(fizz_buzz(15)[-1]))    # expect 'FizzBuzz'
fizz_buzz.py
def fizz_buzz(n):
    # TODO: return list of strings 1..n applying the Fizz/Buzz/FizzBuzz rules
    pass
 
 
# Sample tests (press Run):
print(fizz_buzz(5))         # expect ['1', '2', 'Fizz', '4', 'Buzz']
print(repr(fizz_buzz(15)[-1]))    # expect 'FizzBuzz'
Show solution
python
def fizz_buzz(n):
    result = []
    for i in range(1, n + 1):
        if i % 15 == 0:
            result.append("FizzBuzz")
        elif i % 3 == 0:
            result.append("Fizz")
        elif i % 5 == 0:
            result.append("Buzz")
        else:
            result.append(str(i))
    return result
 
 
print(fizz_buzz(5))         # ['1', '2', 'Fizz', '4', 'Buzz']
print(repr(fizz_buzz(15)[-1]))    # 'FizzBuzz'
python
def fizz_buzz(n):
    result = []
    for i in range(1, n + 1):
        if i % 15 == 0:
            result.append("FizzBuzz")
        elif i % 3 == 0:
            result.append("Fizz")
        elif i % 5 == 0:
            result.append("Buzz")
        else:
            result.append(str(i))
    return result
 
 
print(fizz_buzz(5))         # ['1', '2', 'Fizz', '4', 'Buzz']
print(repr(fizz_buzz(15)[-1]))    # 'FizzBuzz'

Check the 1515 case (both 3 and 5) before the individual cases, or "Fizz""Fizz" and "Buzz""Buzz" will each fire on their own and you’ll never print "FizzBuzz""FizzBuzz". Time: O(n)O(n). Space: O(n)O(n) for the output list.

8. Reverse Linked List — LC 206 — Easy

Open LC 206 on LeetCode

Pattern: In-place pointer rewiring — see In-place Linked List Reversal.

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

reverse_linked_list.py
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
 
def build_list(values):
    head = None
    for v in reversed(values):
        head = ListNode(v, head)
    return head
 
 
def to_list(head):
    values = []
    while head:
        values.append(head.val)
        head = head.next
    return values
 
 
def reverse_list(head):
    # TODO: reverse the linked list in place and return the new head
    pass
 
 
# Sample tests (press Run):
print(to_list(reverse_list(build_list([1, 2, 3, 4, 5]))))   # expect [5, 4, 3, 2, 1]
print(to_list(reverse_list(build_list([]))))                  # expect []
reverse_linked_list.py
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
 
def build_list(values):
    head = None
    for v in reversed(values):
        head = ListNode(v, head)
    return head
 
 
def to_list(head):
    values = []
    while head:
        values.append(head.val)
        head = head.next
    return values
 
 
def reverse_list(head):
    # TODO: reverse the linked list in place and return the new head
    pass
 
 
# Sample tests (press Run):
print(to_list(reverse_list(build_list([1, 2, 3, 4, 5]))))   # expect [5, 4, 3, 2, 1]
print(to_list(reverse_list(build_list([]))))                  # expect []
Show solution
python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
 
def build_list(values):
    head = None
    for v in reversed(values):
        head = ListNode(v, head)
    return head
 
 
def to_list(head):
    values = []
    while head:
        values.append(head.val)
        head = head.next
    return values
 
 
def reverse_list(head):
    prev = None
    current = head
    while current:
        nxt = current.next     # save the rest of the list before overwriting .next
        current.next = prev    # point backwards
        prev = current
        current = nxt
    return prev
 
 
print(to_list(reverse_list(build_list([1, 2, 3, 4, 5]))))   # [5, 4, 3, 2, 1]
print(to_list(reverse_list(build_list([]))))                  # []
python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
 
def build_list(values):
    head = None
    for v in reversed(values):
        head = ListNode(v, head)
    return head
 
 
def to_list(head):
    values = []
    while head:
        values.append(head.val)
        head = head.next
    return values
 
 
def reverse_list(head):
    prev = None
    current = head
    while current:
        nxt = current.next     # save the rest of the list before overwriting .next
        current.next = prev    # point backwards
        prev = current
        current = nxt
    return prev
 
 
print(to_list(reverse_list(build_list([1, 2, 3, 4, 5]))))   # [5, 4, 3, 2, 1]
print(to_list(reverse_list(build_list([]))))                  # []

Three pointers (prevprev, currentcurrent, nxtnxt) walk the list once, flipping one .next.next link per step. No extra list or recursion needed. Time: O(n)O(n). Space: O(1)O(1).

Recap

  • Eight easy-to-medium problems, one of each core flavor: hash maps, two pointers, Kadane’s DP, plain simulation, and linked-list rewiring.
  • The loop is always the same: read the stub, find the # TODO# TODO, press Run, compare the printed output to the # expect# expect comment, open Show solution only if you’re stuck.
  • Once your output matches locally, paste the solution into the real problem on LeetCode — this page’s judge is stdlib-only and doesn’t replace the hidden test suite there.

Next: Arrays and Strings Problem Set — the same loop, with harder array/string problems that escalate from sorted-array two pointers all the way to Minimum Window Substring.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did