You don't need to memorize a thousand puzzles. Most coding problems are solved by a handful of patterns. Learn the pattern, and you can crack a whole family of problems!
This capstone brings together everything: loops, hash tables, two-finger tricks, and smart thinking to turn slow O(nยฒ) solutions into fast O(n) ones.
๐๐ Pattern 1: Two Pointers
Use two indexes that move toward each other (or in the same direction). Great for sorted lists and reversing.
def is_palindrome(s):
left, right = 0, len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
print(is_palindrome("racecar")) # True
๐ก When to reach for it
Two pointers turn many O(nยฒ) "check every pair" problems into O(n).
๐ช Pattern 2: Sliding Window
Keep a "window" over part of a list and slide it along, updating a running total instead of recomputing from scratch.
def max_sum(nums, k):
window = sum(nums[:k])
best = window
for i in range(k, len(nums)):
window += nums[i] - nums[i - k] # slide!
best = max(best, window)
return best
print(max_sum([1, 4, 2, 10, 2], 2)) # 12
๐๏ธ Pattern 3: Hash for Speed
When you find yourself searching "have I seen this before?", a set or dict turns that lookup into O(1).
def first_repeat(nums):
seen = set()
for n in nums:
if n in seen:
return n
seen.add(n)
return None
๐ Your algorithm toolkit
Big-O โ measure how an algorithm scales.
Recursion โ solve a problem with smaller copies of itself.
Stacks, Queues, Linked Lists โ organize data your way.
Hash tables & Trees โ instant lookups and branching data.
Patterns โ two pointers, sliding window, hashing for speed.
๐ You've finished the Algorithms track. You now think like a real computer scientist!
๐ฎ Final Boss Challenges!
Use the patterns to slay these. ๐
๐
Task 1: Palindrome with Two Pointers
Medium
Finish is_palindrome using two pointers moving inward. "racecar" โ True, "hello" โ False.
def is_palindrome(s):
left, right = 0, len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
print(is_palindrome("racecar"))
print(is_palindrome("hello"))
๐ช
Task 2: Best Window Sum
Challenge
Find the biggest sum of any k=2 neighbours in [1, 4, 2, 10, 2] using a sliding window. Answer: 12 (10 + 2).
def max_sum(nums, k):
window = sum(nums[:k])
best = window
for i in range(k, len(nums)):
window += nums[i] - nums[i - k]
best = max(best, window)
return best
print(max_sum([1, 4, 2, 10, 2], 2))
๐ฏ
Task 3: First Repeated Number
Boss
Return the first number that appears twice in [5, 1, 4, 4, 2, 1] using a set for O(1) lookups. Answer: 4.
def first_repeat(nums):
seen = set()
for n in nums:
if n in seen:
return n
seen.add(n)
return None
print(first_repeat([5, 1, 4, 4, 2, 1]))
๐๏ธ Extra Practice โ Algorithm Reps
Interview problems reuse the same handful of tricks. Practice each pattern until you recognize it in one glance.
๐
Task 4: Two Pointers: Pair Sum
Medium
In the sorted list [1, 3, 5, 8, 11], find two numbers that add up to 14 using one pointer at each end: move the left one right when the sum is too small, the right one left when it is too big. Print the pair like 3 11.
3 11
numbers = [1, 3, 5, 8, 11]
target = 14
left, right = 0, len(numbers) - 1
while left < right:
total = numbers[left] + numbers[right]
if total == target:
print(numbers[left], numbers[right])
break
elif total < target:
left += 1
else:
right -= 1
๐ช
Task 5: Sliding Window Average
Medium
Find the highest average of any 3 neighboring numbers in [1, 9, 2, 8, 3, 7]. Slide a window of 3: add the new number, subtract the one that left. Print the best average rounded to 2 decimals.
6.33
numbers = [1, 9, 2, 8, 3, 7]
k = 3
window = sum(numbers[:k])
best = window
for i in range(k, len(numbers)):
window += numbers[i] - numbers[i - k]
if window > best:
best = window
print(round(best / k, 2))
๐งพ
Task 6: Prefix Sums
Tricky
Build a running-total list from [2, 4, 6, 8] so that prefix[i] is the sum of everything up to i. Print the prefix list, then use it to answer "what is the sum from index 1 to 3?" instantly.
[0, 2, 6, 12, 20]
18
numbers = [2, 4, 6, 8]
prefix = [0]
for n in numbers:
prefix.append(prefix[-1] + n)
print(prefix)
print(prefix[4] - prefix[1])
๐
Task 7: Frequency Counter Face-Off
Medium
Check whether [1, 2, 3, 2] and [2, 1, 2, 3] contain exactly the same numbers the same number of times โ using two count dictionaries instead of nested loops. Print True, then compare against [1, 2, 3, 3] and print False.
True
False
def counts(items):
result = {}
for item in items:
result[item] = result.get(item, 0) + 1
return result
def same_contents(a, b):
return counts(a) == counts(b)
print(same_contents([1, 2, 3, 2], [2, 1, 2, 3]))
print(same_contents([1, 2, 3, 2], [1, 2, 3, 3]))
๐
Task 8: Fast and Slow Pointers
Tricky
Without using len() twice, find the middle item of [10, 20, 30, 40, 50]: move a slow index by 1 and a fast index by 2 until the fast one runs off the end. Print the middle value.
30
items = [10, 20, 30, 40, 50]
slow = 0
fast = 0
while fast < len(items) and fast + 1 < len(items):
slow += 1
fast += 2
print(items[slow])
๐
Task 9: Boss Level: Longest Run of Different Letters
Boss
Find the length of the longest stretch of "abcabcbb" with no repeated letter โ the classic sliding-window question. Keep a start index and a dictionary of where each letter was last seen. Print the answer (it is 3).
3
text = "abcabcbb"
last_seen = {}
start = 0
best = 0
for i, ch in enumerate(text):
if ch in last_seen and last_seen[ch] >= start:
start = last_seen[ch] + 1
last_seen[ch] = i
best = max(best, i - start + 1)
print(best)