Beginner

Easy Problems (1-10)

These ten problems are the foundation. Every AI engineer should be able to solve them cleanly in under 15 minutes each. They cover hash maps, stacks, two pointers, linked lists, trees, and dynamic programming basics — patterns that appear in every interview.

Problem 1: Two Sum

LeetCode #1 — Given an array of integers nums and an integer target, return indices of the two numbers that add up to target. You may assume each input has exactly one solution and you may not use the same element twice.

Pattern: Hash Map — Use a dictionary to store complements for O(1) lookup.

ML Context: Hash-based lookups power feature stores in recommendation systems. When you retrieve user features during inference, you need O(1) access, exactly like this problem.

def twoSum(nums, target):
    """
    Time: O(n) - single pass through array
    Space: O(n) - hash map stores up to n elements
    """
    seen = {}  # value -> index
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i

# Example:
# twoSum([2, 7, 11, 15], 9) -> [0, 1]
# twoSum([3, 2, 4], 6) -> [1, 2]
💡
Key insight: The brute force is O(n^2) with two nested loops. The hash map reduces the inner loop to O(1) by trading space for time. This space-time tradeoff is the most common optimization pattern in coding interviews.

Problem 2: Valid Parentheses

LeetCode #20 — Given a string containing just the characters (, ), {, }, [, ], determine if the input string is valid. An input string is valid if open brackets are closed by the same type and in the correct order.

Pattern: Stack — Push opening brackets, pop and match on closing brackets.

ML Context: Compilers and parsers for ML frameworks (like ONNX model definitions or TensorFlow graph serialization) use stack-based matching to validate nested structures.

def isValid(s):
    """
    Time: O(n) - single pass through string
    Space: O(n) - stack stores up to n/2 brackets
    """
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    for char in s:
        if char in mapping:
            if not stack or stack[-1] != mapping[char]:
                return False
            stack.pop()
        else:
            stack.append(char)
    return len(stack) == 0

# isValid("()[]{}") -> True
# isValid("(]") -> False
# isValid("([)]") -> False

Problem 3: Merge Two Sorted Lists

LeetCode #21 — Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.

Pattern: Two Pointers — Compare heads of both lists, advance the smaller one.

ML Context: Merging sorted sequences is fundamental to merge sort, which is used in external sorting for large datasets that do not fit in memory — common in data preprocessing pipelines.

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def mergeTwoLists(list1, list2):
    """
    Time: O(n + m) where n, m are list lengths
    Space: O(1) - we reuse existing nodes
    """
    dummy = ListNode(0)
    current = dummy
    while list1 and list2:
        if list1.val <= list2.val:
            current.next = list1
            list1 = list1.next
        else:
            current.next = list2
            list2 = list2.next
        current = current.next
    current.next = list1 or list2
    return dummy.next

Problem 4: Best Time to Buy and Sell Stock

LeetCode #121 — Given an array prices where prices[i] is the price of a stock on day i, find the maximum profit from one buy and one sell. You must buy before you sell.

Pattern: Track minimum so far — At each price, compute profit if selling today, update minimum.

ML Context: This min-tracking pattern appears in training loss monitoring. You track the best validation loss seen so far (early stopping) using the exact same logic.

def maxProfit(prices):
    """
    Time: O(n) - single pass
    Space: O(1) - two variables
    """
    min_price = float('inf')
    max_profit = 0
    for price in prices:
        min_price = min(min_price, price)
        max_profit = max(max_profit, price - min_price)
    return max_profit

# maxProfit([7,1,5,3,6,4]) -> 5  (buy at 1, sell at 6)
# maxProfit([7,6,4,3,1]) -> 0    (no profitable transaction)

Problem 5: Valid Palindrome

LeetCode #125 — Given a string s, return true if it is a palindrome after converting to lowercase and removing non-alphanumeric characters.

Pattern: Two Pointers — Compare characters from both ends, skip non-alphanumeric.

ML Context: Text preprocessing is fundamental to NLP pipelines. Normalizing and cleaning strings before tokenization uses similar character-level logic.

def isPalindrome(s):
    """
    Time: O(n) - two pointers meet in the middle
    Space: O(1) - in-place comparison
    """
    left, right = 0, len(s) - 1
    while left < right:
        while left < right and not s[left].isalnum():
            left += 1
        while left < right and not s[right].isalnum():
            right -= 1
        if s[left].lower() != s[right].lower():
            return False
        left += 1
        right -= 1
    return True

# isPalindrome("A man, a plan, a canal: Panama") -> True
# isPalindrome("race a car") -> False

Problem 6: Linked List Cycle

LeetCode #141 — Given head, the head of a linked list, determine if the linked list has a cycle in it.

Pattern: Fast/Slow Pointers (Floyd's Cycle Detection) — Two pointers at different speeds; if they meet, there is a cycle.

ML Context: Cycle detection in computational graphs prevents infinite loops during backpropagation. PyTorch and TensorFlow both need to detect cycles when building autograd graphs.

def hasCycle(head):
    """
    Time: O(n) - fast pointer traverses at most 2n
    Space: O(1) - two pointers only
    """
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False

Problem 7: Climbing Stairs

LeetCode #70 — You are climbing a staircase with n steps. Each time you can climb 1 or 2 steps. How many distinct ways can you reach the top?

Pattern: Dynamic Programming — dp[i] = dp[i-1] + dp[i-2]. This is Fibonacci with different base cases.

ML Context: This recurrence structure appears in sequence modeling. The Viterbi algorithm for HMMs uses similar DP to find the most likely sequence of hidden states.

def climbStairs(n):
    """
    Time: O(n) - single pass
    Space: O(1) - two variables
    """
    if n <= 2:
        return n
    prev2, prev1 = 1, 2
    for i in range(3, n + 1):
        curr = prev1 + prev2
        prev2 = prev1
        prev1 = curr
    return prev1

# climbStairs(2) -> 2  (1+1 or 2)
# climbStairs(3) -> 3  (1+1+1, 1+2, 2+1)
# climbStairs(10) -> 89

Problem 8: Binary Tree Inorder Traversal

LeetCode #94 — Given the root of a binary tree, return the inorder traversal of its nodes' values (left, root, right).

Pattern: Tree Traversal — Recursive or iterative with a stack.

ML Context: Decision trees and random forests traverse tree structures during both training and inference. Understanding tree traversal orders is essential for implementing these models from scratch.

def inorderTraversal(root):
    """
    Iterative approach using explicit stack.
    Time: O(n) - visit every node
    Space: O(h) - stack depth equals tree height
    """
    result = []
    stack = []
    current = root
    while current or stack:
        while current:
            stack.append(current)
            current = current.left
        current = stack.pop()
        result.append(current.val)
        current = current.right
    return result

# Recursive alternative (simpler but uses call stack):
def inorderRecursive(root):
    if not root:
        return []
    return inorderRecursive(root.left) + [root.val] + inorderRecursive(root.right)

Problem 9: Maximum Subarray

LeetCode #53 — Given an integer array nums, find the subarray with the largest sum and return its sum.

Pattern: Kadane's Algorithm — Track current sum and maximum sum. Reset current sum when it drops below zero.

ML Context: Kadane's algorithm is used in time-series anomaly detection to find the period with the largest cumulative deviation. It also appears in feature importance analysis on sequential data.

def maxSubArray(nums):
    """
    Kadane's Algorithm
    Time: O(n) - single pass
    Space: O(1) - two variables
    """
    max_sum = nums[0]
    current_sum = nums[0]
    for i in range(1, len(nums)):
        current_sum = max(nums[i], current_sum + nums[i])
        max_sum = max(max_sum, current_sum)
    return max_sum

# maxSubArray([-2,1,-3,4,-1,2,1,-5,4]) -> 6  (subarray [4,-1,2,1])
# maxSubArray([1]) -> 1
# maxSubArray([-1]) -> -1

Problem 10: Contains Duplicate

LeetCode #217 — Given an integer array nums, return true if any value appears at least twice.

Pattern: Hash Set — Add each element to a set; if it already exists, return True.

ML Context: Deduplication is critical in ML data pipelines. Training on duplicate data causes the model to overfit to repeated examples. Hash-based deduplication is the standard approach in dataset curation.

def containsDuplicate(nums):
    """
    Time: O(n) - single pass
    Space: O(n) - set stores up to n elements
    """
    seen = set()
    for num in nums:
        if num in seen:
            return True
        seen.add(num)
    return False

# Alternative one-liner:
# def containsDuplicate(nums): return len(nums) != len(set(nums))

# containsDuplicate([1,2,3,1]) -> True
# containsDuplicate([1,2,3,4]) -> False

Key Takeaways

  • Hash maps and sets are the most powerful tools for reducing O(n^2) to O(n). Problems 1, 10, and many medium problems rely on this pattern.
  • Two pointers (Problems 3, 5, 6) work whenever the data is sorted or you need to compare elements from different positions.
  • Kadane's algorithm (Problem 9) is the simplest form of DP and a building block for harder DP problems.
  • Stack (Problem 2) is the go-to for matching nested structures. You will see it again in harder problems like Trapping Rain Water.
  • Every easy problem has a direct connection to real AI/ML systems. Understanding these patterns makes you a better ML engineer, not just a better interviewee.