10 Common Coding Interview Mistakes and How to Avoid Them
From jumping into code too quickly to ignoring edge cases — the most frequent interview mistakes and practical fixes.
Technical interviews are not just about solving the problem. Plenty of candidates who know the algorithm still fail because of how they approach the interview. These are the ten mistakes that come up most often.
1. Jumping Into Code Without a Plan
You read the problem and start typing. Three minutes later, your approach does not work, but you have 20 lines committed.
Fix: Spend 3-5 minutes on a plan. State the approach out loud. Write pseudocode. Only code when the interviewer confirms your direction.
Practical Depth: A good plan involves identifying the core algorithm or data structure. For example, if the problem is "Find two numbers in an array that sum to a target," your plan should explicitly state you'll use a hash map for O(1) lookups. Write this as pseudocode before touching the keyboard.
Pseudocode Example for Two Sum:
function twoSum(nums, target):
create an empty map (value -> index)
for each index i and number num in nums:
calculate complement = target - num
if complement is in map:
return [map[complement], i]
else:
add num and i to the map
return empty list (no solution found)
2. Not Clarifying the Problem
Interviewers leave requirements vague deliberately. Wrong assumptions mean solving the wrong problem.
Fix: Ask: "Can the array contain negatives?" "Is the string ASCII?" "What if there are multiple valid answers?" Write down agreed constraints.
Practical Depth: Different constraints lead to different optimal solutions. For a "find the maximum subarray sum" problem (Kadane's Algorithm), clarifying if all numbers can be negative changes the base logic. Always confirm input size, value ranges, and expected output format.
# Example: Clarifying if we need to handle all-negative arrays for Kadane's Algorithm
def max_subarray_sum(nums):
"""
Assumptions clarified: Input can contain negatives.
If all numbers are negative, return the least negative (maximum) number.
"""
if not nums:
return 0 # Or handle as per clarified requirement
current_max = global_max = nums[0]
for num in nums[1:]:
current_max = max(num, current_max + num)
global_max = max(global_max, current_max)
return global_max
3. Not Walking Through Examples
Jumping from reading to coding without tracing examples leads to bugs you could have caught early.
Fix: Walk through given examples step by step. Create your own edge case (empty input, single element) and trace through that too.
Practical Depth: Use a systematic method. For a binary search problem, take the example array [1, 3, 5, 7, 9] and target 5. Manually trace the indices (low, high, mid) and value comparisons. This reveals the loop condition (low <= high) and how to update pointers (mid ± 1).
# Binary Search with manual tracing example
def binary_search(arr, target):
"""
Example Walkthrough for arr = [1, 3, 5, 7, 9], target = 5
Step 1: low=0, high=4, mid=2 -> arr[2]=5 == target -> return 2
"""
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
4. Poor Time Management
Spending 25 minutes on approach with 5 minutes left to code. Or finishing code with no time to test.
Fix: For a 45-minute interview: 5 min understand, 5 min plan, 20 min code, 10 min test, 5 min follow-ups. If stuck after 10 minutes, ask for a hint.
Practical Depth: Break down the coding phase. For a medium problem like "Implement a stack with getMin() in O(1) time," you should allocate time to define the class structure, implement core methods (push, pop, top, getMin), and then test. Having a mental checklist for each phase prevents over-investing in one part.
5. Coding in Silence
Fifteen minutes of quiet typing. The interviewer has no idea what you are thinking.
Fix: Narrate continuously. "I am iterating with two pointers. Left starts at 0, right at the end." Verbalizing forces clearer thinking and helps the interviewer give useful hints.
Practical Depth: Good narration includes stating your intent, explaining data structure choices, and acknowledging trade-offs. For example, while solving a sliding window problem: "I'll use a hash map to track character frequencies in the current window. This gives O(1) lookups but uses O(k) space for the window size."
# Solving "Longest Substring Without Repeating Characters" with narration
def length_of_longest_substring(s: str) -> int:
# Narration: "I'll use a sliding window with a set to track unique characters."
char_set = set()
left = 0
max_length = 0
# Narration: "Right pointer expands the window."
for right in range(len(s)):
# Narration: "If duplicate found, shrink window from left until it's gone."
while s[right] in char_set:
char_set.remove(s[left])
left += 1
# Narration: "Add current char and update max length."
char_set.add(s[right])
max_length = max(max_length, right - left + 1)
return max_length
6. Overcomplicating the Solution
Reaching for a segment tree when a prefix sum works.
Fix: Start with the simplest approach. State the brute force first: "The naive approach is O(n^2). I can optimize to O(n) with a hash map." Interviewers appreciate seeing you identify the simple solution before optimizing.
Practical Depth: For the problem "Find a subarray with a given sum," the brute force checks all subarrays (O(n²)). The optimal approach uses a hash map with prefix sums (O(n)). Demonstrating this progression shows structured problem-solving.
# Subarray Sum Equals K - From Brute Force to Optimal
def subarray_sum_brute_force(nums, k):
"""Brute Force O(n^2) approach."""
count = 0
n = len(nums)
for start in range(n):
current_sum = 0
for end in range(start, n):
current_sum += nums[end]
if current_sum == k:
count += 1
return count
def subarray_sum_optimal(nums, k):
"""Optimal O(n) approach using prefix sum hash map."""
count = 0
prefix_sum = 0
# Map: prefix_sum_value -> frequency of occurrences
prefix_map = {0: 1} # Base case: prefix sum 0 appears once
for num in nums:
prefix_sum += num
# Check if (prefix_sum - k) exists in map
count += prefix_map.get(prefix_sum - k, 0)
# Update the frequency of the current prefix sum
prefix_map[prefix_sum] = prefix_map.get(prefix_sum, 0) + 1
return count
7. Ignoring Edge Cases
Your solution works for the happy path but crashes on empty input, single elements, or all-negative numbers.
Fix: After coding, check a mental list: empty input, single element, all same values, large values, negative numbers. For strings: empty string, single character. Handle these or acknowledge them verbally.
Practical Depth: Create a standard edge case checklist. For array/list problems: [], [1], [1,1,1], [0,0,0], [-1,-2,-3], large n. For tree problems: null root, single node, skewed tree (like a linked list). For graph problems: single node, disconnected graph, cycles.
# Example: Handling edge cases in a function to find the second largest number
def find_second_largest(nums):
"""Handles edge cases explicitly."""
if not nums or len(nums) < 2:
# Clarify what to return: None, -1, or raise exception?
return None # Based on clarified requirement
first = second = float('-inf')
for num in nums:
if num > first:
second = first
first = num
elif num > second and num != first:
second = num
# Edge case: all elements are the same
if second == float('-inf'):
return None # No distinct second largest
return second
8. Not Testing Your Code
You write the solution and declare "I think that works."
Fix: Trace through your code line by line with a small example, tracking variable values. Then test an edge case. Finding and fixing bugs during testing is a positive signal.
Practical Depth: Use a systematic testing method. For a function that reverses a linked list, test with: a list of multiple nodes (1->2->3), a single node (5), and an empty list (null). For each test, manually step through the pointer manipulations.
# Example: Testing a linked list reversal thoroughly
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list(head):
"""Iteratively reverses a linked list."""
prev = None
current = head
while current:
next_temp = current.next
current.next = prev
prev = current
current = next_temp
return prev # New head
# Test Cases to walk through:
# 1. Multiple nodes: 1 -> 2 -> 3 -> None
# Step: prev=None, curr=1 -> prev=1, curr=2 -> prev=2, curr=3 -> prev=3, curr=None
# Returns: 3 -> 2 -> 1 -> None
# 2. Single node: 5 -> None
# Step: prev=None, curr=5 -> prev=5, curr=None
# Returns: 5 -> None
# 3. Empty list: None
# Step: loop never enters, returns None
9. Giving Up Too Easily
You hit a wall and say "I do not know."
Fix: Verbalize what you know: "I need to find pairs summing to K. A hash map gives O(n) lookups. I am not sure about duplicates." Try brute force as a starting point. Ask clarifying questions about the sticking point.
Practical Depth: When stuck, decompose the problem. For "Find the median of two sorted arrays," start by discussing the naive approach: merge both arrays and find the median (O(m+n) time, O(m+n) space). Then discuss the optimization challenge: achieving O(log(min(m, n))) with binary search. This shows engagement even if the optimal solution isn't fully formed.
10. Not Analyzing Complexity
The interviewer asks "What is the time complexity?" and you guess wrong.
Fix: Practice analyzing every solution you write. State complexity proactively: "The outer loop is O(n), hash lookup is O(1), so total is O(n). Space is O(n) for the map." See the time complexity reference for details.
Practical Depth: Complexity analysis must consider worst-case, average-case, and amortized time. For example, operations on a dynamic array (like Python list) have amortized O(1) for append. Also, remember to analyze auxiliary space (extra space used by the algorithm) separately from input space.
# Example: Complexity analysis for a graph BFS
from collections import deque
def bfs_shortest_path(graph, start, end):
"""
Time Complexity: O(V + E)
- Each vertex (V) is enqueued/dequeued once -> O(V)
- Each edge (E) is examined once in adjacency list traversal -> O(E)
Space Complexity: O(V)
- Queue can hold up to V vertices in worst case.
- Visited set holds up to V vertices.
"""
if start == end:
return [start]
visited = {start}
queue = deque([(start, [start])]) # (node, path)
while queue:
node, path = queue.popleft()
for neighbor in graph.get(node, []):
if neighbor == end:
return path + [neighbor]
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, path + [neighbor]))
return [] # No path
The Process
Build a reliable process and practice it during every LeetCode session:
- Read and clarify (2-3 min): Restate the problem in your own words. Ask specific questions about input constraints, edge cases, and output format. Write down the agreed assumptions.
- Work through examples (3 min): Use the given examples. Then create your own small, typical case and an edge case. Trace the expected output manually.
- Plan approach, state complexity (3-5 min): Verbally outline at least two approaches: a brute force and an optimized one. Discuss trade-offs in time and space complexity. Get confirmation from the interviewer before coding.
- Code while narrating (15-20 min): Write clean, modular code. Name variables meaningfully. Explain each logical block as you write it. If you realize a better approach mid-way, discuss the change with the interviewer.
- Test with examples and edge cases (5-10 min): Run your code against the initial examples. Then test the edge cases you identified earlier. Verbally walk through the code execution, tracking key variable states. Fix any bugs you find.
The best way to pressure-test your process is mock interviews. For more on this, see the mock interview guide.