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# expectcomment. - 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:
- A problem statement with the constraints that matter.
- A runnable stub — a function with a
# TODO# TODOand someprint(...)print(...)calls under a# Sample tests# Sample testscomment. Press Run on the code block to execute it right here in the browser. - 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
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.
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]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
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]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: . Space: .
2. Valid Palindrome — LC 125 — Easy
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.
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 Truedef 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 TrueShow solution
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(" ")) # Truedef 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(" ")) # TrueClean once, then close in from both ends — the moment two characters
disagree, it can’t be a palindrome. Time: . Space:
for the cleaned copy (can be made by indexing into ss directly and
skipping non-alphanumeric characters as you go).
3. Best Time to Buy and Sell Stock — LC 121 — Easy
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.
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 0def 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 0Show solution
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])) # 0def 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])) # 0Track 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: . Space: .
4. Contains Duplicate — LC 217 — Easy
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.
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 Falsedef 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 FalseShow solution
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])) # Falsedef 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])) # FalseA set gives average membership checks, so one linear pass is enough. Time: . Space: .
5. Valid Anagram — LC 242 — Easy
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).
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 Falsedef 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 FalseShow solution
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")) # Falsefrom 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")) # FalseTwo strings are anagrams exactly when their character-frequency maps are
equal — CounterCounter builds that map for you. Time: . Space:
(bounded alphabet) or for a general Unicode alphabet.
6. Maximum Subarray (Kadane) — LC 53 — Medium
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.
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 23def 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 23Show solution
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])) # 23def 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])) # 23Kadane’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: .
Space: .
7. Fizz Buzz — LC 412 — Easy
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.
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'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
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'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: . Space: for the output list.
8. Reverse Linked List — LC 206 — Easy
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.
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 []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
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([])))) # []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:
. Space: .
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# expectcomment, 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 coffeeWas this page helpful?
Let us know how we did
