← Back to BlogInterviews · 18 min read

From FizzBuzz to LRU Cache: Coding Interview Questions in 5 Levels

A layered preparation guide — beginner problems, array patterns, HashMaps, linked lists, and a full LRU Cache implementation with complexity analysis and the mistakes that quietly tank interviews.

KPBy Kajal Pansuriya·Published May 22, 2026·18-minute read

Technical interviews are designed to evaluate more than whether you can write code. Interviewers want to understand how you think, how you approach problems, how you optimise solutions, and how well you communicate under pressure. One of the most effective ways to prepare is to learn problems in layers, starting with simple conditional logic and ending with system-style design questions.

This guide walks through five levels of interview preparation — beginner problems, intermediate array questions, HashMap patterns, linked list fundamentals, and a deep dive into the LRU Cache. Along the way we cover time and space complexity, common interview mistakes, real expectations, and communication strategies. Whether you are preparing for your first internship interview or targeting top tech companies, understanding these concepts deeply will dramatically improve your confidence.

1 Level 1 — Beginner Problems

Beginner coding interview questions are not designed to trick you. They test whether you can understand the requirements, write syntactically correct code, use basic control flow, handle edge cases, and explain your logic. Many candidates underestimate beginner problems and fail because they rush.

Common beginner questions include FizzBuzz, palindrome checks, string reversal, finding the maximum in an array, vowel counting, prime checks, and factorials. The most famous is FizzBuzz — and it filters out more candidates than it should.

The problem. Print numbers from 1 to n. Replace multiples of 3 with Fizz, multiples of 5 with Buzz, and multiples of both with FizzBuzz.

The wrong logic most candidates write. Notice the bug — multiples of 15 are caught by the first branch before the FizzBuzz branch can ever fire.

if n % 3 == 0:
    print("Fizz")
elif n % 5 == 0:
    print("Buzz")
elif n % 15 == 0:    # never reached
    print("FizzBuzz")

Correct ordering. Check the most specific condition first.

for i in range(1, n + 1):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

Time complexity O(n), space O(1). The interviewer is not impressed by a clever solution here — they are watching whether you talk through the ordering decision before you write any code.

2 Level 2 — Intermediate Array Questions

Arrays are the most important data structure in coding interviews. If beginner questions test the basics, array problems test pattern recognition, optimisation ability, and algorithmic thinking. Most interview rounds contain at least one array problem.

Popular questions include Two Sum, Best Time to Buy and Sell Stock, Maximum Subarray, Move Zeroes, Merge Intervals, Product of Array Except Self, Rotate Array, and Trapping Rain Water. They all share a hidden theme: an interviewer expects you to start with brute force and then improve.

Two Sum — brute force.

for i in range(len(nums)):
    for j in range(i + 1, len(nums)):
        if nums[i] + nums[j] == target:
            return [i, j]

Time O(n²), space O(1). Interviewers expect candidates to improve this.

Two Sum — HashMap optimisation.

seen = {}

for i, num in enumerate(nums):
    complement = target - num
    if complement in seen:
        return [seen[complement], i]
    seen[num] = i

Time O(n), space O(n). This problem introduces one of the most important interview concepts: trading space for speed.

Sliding window. Useful for continuous subarrays, fixed-size ranges, and dynamic windows. The maximum sum subarray of size k drops from O(n × k) to O(n) with one trick — instead of recomputing each window, slide it by adding the new element and removing the old one.

window_sum = sum(arr[:k])
max_sum    = window_sum

for i in range(k, len(arr)):
    window_sum += arr[i]
    window_sum -= arr[i - k]
    max_sum = max(max_sum, window_sum)

Two pointers. Equally important when an array is sorted, or when checking palindromes, pair searching, or partitioning. The classic palindrome check walks two indices toward the middle.

left, right = 0, len(s) - 1

while left < right:
    if s[left] != s[right]:
        return False
    left  += 1
    right -= 1

return True

Common mistakes in this level: off-by-one errors, ignoring empty arrays, incorrect index handling, and forgetting duplicates. Practising patterns is more valuable than memorising solutions — once you recognise “sliding window” in a problem statement, the rest writes itself.

3 Level 3 — HashMap Patterns

HashMaps are among the most powerful tools in coding interviews. Many otherwise difficult problems become easy once you spot a HashMap pattern. Average-case lookup is O(1), which means you can usually trade memory to drop one full level of time complexity.

The core patterns are frequency counting, prefix sums, fast lookup, grouping, and caching previous results. Each of those names matches a family of common problems.

Frequency counting — Valid Anagram.

from collections import Counter
return Counter(s) == Counter(t)

Two strings are anagrams if their character frequencies match. Interviewers want you to explain why this works, not just that it does.

Prefix sums — Subarray Sum Equals K. Find the number of continuous subarrays summing to k. The trick: store running prefix sums and check whether prefix - k has been seen before.

count       = 0
prefix_sum  = 0
prefix_map  = {0: 1}

for num in nums:
    prefix_sum += num
    if prefix_sum - k in prefix_map:
        count += prefix_map[prefix_sum - k]
    prefix_map[prefix_sum] = prefix_map.get(prefix_sum, 0) + 1

This problem combines prefix sums, HashMap lookup, and mathematical reasoning. Variants of it appear in Google, Meta, and Amazon interviews regularly.

Grouping — Group Anagrams. Sorted characters become a stable key for any anagram family.

from collections import defaultdict

groups = defaultdict(list)
for word in strs:
    key = ''.join(sorted(word))
    groups[key].append(word)

return list(groups.values())

Complexity O(n × k log k) where k is the average word length.

Before reaching for a HashMap, ask yourself four questions: do I need fast lookup, am I counting frequencies, do I need previous results, am I checking duplicates? Any “yes” is a strong signal a HashMap will help.

HashMap operations — insert, lookup, and delete — are all O(1) on average. Worst case becomes O(n) because of collisions, though modern implementations minimise this.

4 Level 4 — Linked List Fundamentals

Linked lists are one of the most misunderstood interview topics. Many developers rarely use them in day-to-day work, but interviewers love them because they test pointer manipulation, memory understanding, logical precision, and edge-case handling.

A linked list is a sequence of nodes, each containing data and a pointer to the next. Unlike arrays, linked lists are not stored contiguously in memory. They have dynamic size and efficient insertion/deletion, at the cost of no random access and extra memory for pointers.

Reverse a linked list — iterative. Among the most common interview questions.

prev    = None
current = head

while current:
    nxt          = current.next
    current.next = prev
    prev         = current
    current      = nxt

return prev

Time O(n), space O(1). Interviewers use this problem to test pointer manipulation skills more than algorithmic creativity.

Fast and slow pointers — Floyd's cycle detection. Detect a cycle, find the middle node, validate a palindrome list — all variations of the same idea.

slow = head
fast = head

while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
    if slow == fast:
        return True

return False

The fast pointer eventually catches the slow one if a cycle exists — otherwise it reaches null. Time O(n), space O(1). Knowing this algorithm by name impresses interviewers because it shows you have seen it before and understood it.

Dummy node technique. Many linked list problems become easier with a sentinel node — it removes the special case of an empty list or a deletion at the head.

dummy      = ListNode(0)
dummy.next = head

Common mistakes: losing references, infinite loops, incorrect pointer updates, null-pointer exceptions, and ignoring empty lists. Draw the pointers on paper before you write code — it sounds slow, but candidates who visualise the list out loud almost always finish faster than candidates who don't.

5 Level 5 — LRU Cache Deep Dive

Now the famous one. The LRU Cache problem combines HashMaps, linked lists, and design thinking. It appears regularly at Google, Amazon, Meta, and other top-tier interviews because it is the smallest possible problem that forces a candidate to combine two data structures deliberately.

The requirement. Both get(key) and put(key, value) must run in O(1). When capacity is exceeded the least recently used item is evicted. LRU caches power browser caches, database buffer pools, operating system page caches, CDNs, and almost every memory tier in production systems.

Why arrays alone fail. Searching is O(n), deletion is O(n), and updating order is inefficient. A linked list alone solves the ordering problem but still costs O(n) to find a key. A HashMap alone solves lookup but cannot track usage order.

The optimal combination. A HashMap maps keys to nodes. A doubly linked list orders nodes from most recently used to least recently used. Every access moves the node to the front; every eviction removes from the back. Both operations are O(1).

Node and class.

class Node:
    def __init__(self, key, value):
        self.key   = key
        self.value = value
        self.prev  = None
        self.next  = None


class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache    = {}

        # Sentinel nodes — left = LRU side, right = MRU side
        self.left  = Node(0, 0)
        self.right = Node(0, 0)
        self.left.next  = self.right
        self.right.prev = self.left

    def remove(self, node):
        prev, nxt = node.prev, node.next
        prev.next, nxt.prev = nxt, prev

    def insert(self, node):
        # Insert just before the right sentinel (MRU end)
        prev, nxt = self.right.prev, self.right
        prev.next = node
        node.prev = prev
        node.next = nxt
        nxt.prev  = node

    def get(self, key):
        if key in self.cache:
            self.remove(self.cache[key])
            self.insert(self.cache[key])
            return self.cache[key].value
        return -1

    def put(self, key, value):
        if key in self.cache:
            self.remove(self.cache[key])

        self.cache[key] = Node(key, value)
        self.insert(self.cache[key])

        if len(self.cache) > self.capacity:
            lru = self.left.next
            self.remove(lru)
            del self.cache[lru.key]

Complexity: get and put are both O(1), space O(capacity).

Interview talking points. Explain why arrays fail, why linked lists alone are not enough, why the list must be doubly linked, and how the HashMap accelerates lookup. Communication here matters as much as code — even a perfect solution loses points when the candidate cannot articulate the trade-offs.

Frequent mistakes. Forgetting to update pointers, removing the wrong node, breaking the chain when the list has one item, mishandling duplicate keys in put, and forgetting to remove the evicted entry from the HashMap when the list pops it.

6 Complexity, Big O, and Why It Always Comes Up

Understanding complexity is essential at every interview level. The question “can this be optimised?” comes up in almost every coding round, and confident Big-O analysis distinguishes candidates more than any single solved problem.

O(1)        constant       — HashMap lookup
O(log n)    logarithmic    — binary search
O(n)        linear         — single-pass loop
O(n log n)  efficient sort — merge sort, quicksort
O(n²)       nested loops   — naive Two Sum
O(2^n)      exponential    — naive recursion

A solution that runs in O(n²) handles ten items fine and times out on ten million. Optimised to O(n), the same code handles massive datasets — and that jump usually requires only the introduction of a HashMap or a sliding window.

Don't ignore space complexity. Recursive solutions use stack space, HashMaps trade memory for speed, and large auxiliary arrays consume RAM. The interviewer wants you to name the trade-off, not pretend it doesn't exist.

7 What Interviewers Actually Evaluate

Coding interviews evaluate problem-solving approach, communication, optimisation ability, debugging skills, confidence, and collaboration. Strong candidates follow a predictable rhythm.

  1. Clarify the problem before writing code.
  2. State the brute-force approach out loud.
  3. Analyse the brute-force complexity.
  4. Optimise gradually, narrating the reasoning.
  5. Test the solution against edge cases.

The most common candidate mistakes. Jumping into code too quickly leads to incorrect assumptions and silent bugs. Ignoring edge cases — empty arrays, single elements, duplicates, negatives — is the single biggest reason interviewers downgrade an otherwise solid round. And silent candidates create uncertainty: interviewers cannot give partial credit for thinking they cannot see.

8 How to Practise Effectively

Do not memorise hundreds of solutions. Memorise patterns — sliding window, two pointers, HashMaps, BFS/DFS, dynamic programming, and greedy algorithms. Patterns transfer across problems in a way that individual solutions never will.

Build interview stamina with timed sessions, whiteboard or shared-editor coding, and mock interviews where you explain aloud. Real interviews are stressful precisely because you must perform while you think — and that performance habit is built through repetition.

A reasonable progression: variables and loops → arrays, strings, HashMaps → linked lists, stacks, queues, trees, graphs → recursion, backtracking, dynamic programming, basic system design. Each layer reuses the layer below it, which is exactly why this article was structured the same way.

If you are practising with a friend, paste your code into a ShareCode editor and walk through it together — the conversation is usually where the real learning happens. We also wrote a longer companion piece on conducting technical interviews online if you are on the hiring side of the table.

Frequently Asked Questions

Why do interviewers still ask FizzBuzz in 2026?
FizzBuzz is not designed to be hard. It is designed to filter out candidates who cannot translate a written specification into working code under mild pressure. Interviewers also watch how you order the conditions, whether you check the divisible-by-15 case first, and how clearly you talk through the loop — all signals that scale to harder problems.
What is the most important data structure for coding interviews?
Arrays and HashMaps. Most intermediate questions reduce to iterating an array once while using a HashMap to remember what you have already seen — Two Sum, Subarray Sum Equals K, Group Anagrams, and Longest Consecutive Sequence are all variations of that single pattern.
Why does an LRU Cache need both a HashMap and a doubly linked list?
The HashMap gives O(1) lookup by key. The doubly linked list gives O(1) insertion, deletion, and node-moving so you can update the usage order without scanning. Either structure on its own forces at least one operation to O(n) — together they hit the constraint for both get and put.
How do I detect a cycle in a linked list?
Use Floyd's tortoise-and-hare algorithm. Move a slow pointer one step at a time and a fast pointer two steps. If the list has a cycle the fast pointer will eventually lap the slow pointer and they will meet. If the fast pointer reaches null, there is no cycle. Time O(n), space O(1).
What do interviewers actually evaluate during a coding interview?
Roughly four things: whether you clarify the problem before coding, whether you can articulate a brute-force solution and then improve it, whether your code handles edge cases (empty input, duplicates, single element), and whether you communicate trade-offs. Silent candidates who write perfect code often score lower than candidates who narrate a reasonable solution.
KP

About the author — Kajal Pansuriya

Kajal is a software engineer who has sat through more than fifty technical interview loops on both sides of the table. She writes interview-prep guides for the ShareCode blog. Every problem and complexity analysis in this article was pulled from real rounds at product companies across India and the US.

Final Thoughts

The journey from FizzBuzz to LRU Cache mirrors the evolution of a software engineer's thinking. At first, interview questions feel like isolated puzzles. Eventually you start seeing the patterns — arrays teach iteration, HashMaps teach optimisation, linked lists teach pointer logic, and the LRU Cache teaches system design thinking inside a single function.

You do not need to solve the hardest problems first. Build strong fundamentals, learn patterns deeply, practise explaining solutions out loud, and review mistakes carefully. A candidate who clearly communicates a reasonable solution almost always outperforms a silent candidate writing complex code. The path is not really about algorithms — it is about learning to think like an engineer.

Practise coding interviews in a shared editor

Open a ShareCode editor, paste any problem from this guide, and send the URL to a study partner. Real-time cursors, no installs, free forever.

Open a practice code space