Are you preparing for a coding interview at a top tech company? Whether you’re aiming for a position at a FAANG company (Facebook, Amazon, Apple, Netflix, Google) or any other tech giant, it’s crucial to be well-prepared for the technical interview. In this comprehensive guide, we’ll explore the 20 most common coding interview questions, provide insights on how to approach them, and offer tips to help you succeed in your next interview.

Why Coding Interviews Matter

Coding interviews are a critical part of the hiring process for software engineering positions. They allow companies to assess a candidate’s problem-solving skills, coding ability, and algorithmic thinking. By understanding and practicing these common questions, you’ll be better equipped to showcase your skills and land your dream job.

The 20 Most Common Coding Interview Questions

Let’s dive into the top 20 coding interview questions you’re likely to encounter:

1. Two Sum

Given an array of integers and a target sum, return the indices of two numbers in the array that add up to the target.

def two_sum(nums, target):
    num_dict = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in num_dict:
            return [num_dict[complement], i]
        num_dict[num] = i
    return []

# Example usage
print(two_sum([2, 7, 11, 15], 9))  # Output: [0, 1]

2. Reverse a Linked List

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 reverse_linked_list(head):
    prev = None
    current = head
    while current:
        next_node = current.next
        current.next = prev
        prev = current
        current = next_node
    return prev

# Example usage
# Create a linked list: 1 -> 2 -> 3 -> 4 -> 5
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)

# Reverse the linked list
new_head = reverse_linked_list(head)

# Print the reversed list
current = new_head
while current:
    print(current.val, end=" ")
    current = current.next
# Output: 5 4 3 2 1

3. Valid Parentheses

Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[‘ and ‘]’, determine if the input string is valid. An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.
def is_valid_parentheses(s):
    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

# Example usage
print(is_valid_parentheses("()[]{}"))  # Output: True
print(is_valid_parentheses("([)]"))    # Output: False

4. Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new sorted list.

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

def merge_two_lists(l1, l2):
    dummy = ListNode(0)
    current = dummy
    
    while l1 and l2:
        if l1.val < l2.val:
            current.next = l1
            l1 = l1.next
        else:
            current.next = l2
            l2 = l2.next
        current = current.next
    
    current.next = l1 if l1 else l2
    return dummy.next

# Example usage
# Create two sorted linked lists
l1 = ListNode(1)
l1.next = ListNode(2)
l1.next.next = ListNode(4)

l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)

# Merge the lists
merged = merge_two_lists(l1, l2)

# Print the merged list
current = merged
while current:
    print(current.val, end=" ")
    current = current.next
# Output: 1 1 2 3 4 4

5. Maximum Subarray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

def max_subarray(nums):
    max_sum = current_sum = nums[0]
    for num in nums[1:]:
        current_sum = max(num, current_sum + num)
        max_sum = max(max_sum, current_sum)
    return max_sum

# Example usage
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))  # Output: 6

6. Binary Tree Level Order Traversal

Given a binary tree, return the level order traversal of its nodes’ values. (i.e., from left to right, level by level)

from collections import deque

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def level_order_traversal(root):
    if not root:
        return []
    
    result = []
    queue = deque([root])
    
    while queue:
        level_size = len(queue)
        level = []
        
        for _ in range(level_size):
            node = queue.popleft()
            level.append(node.val)
            
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        
        result.append(level)
    
    return result

# Example usage
# Create a binary tree
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)

print(level_order_traversal(root))
# Output: [[3], [9, 20], [15, 7]]

7. Implement a Trie (Prefix Tree)

Implement a trie with insert, search, and startsWith methods.

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_end_of_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()
    
    def insert(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end_of_word = True
    
    def search(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end_of_word
    
    def starts_with(self, prefix):
        node = self.root
        for char in prefix:
            if char not in node.children:
                return False
            node = node.children[char]
        return True

# Example usage
trie = Trie()
trie.insert("apple")
print(trie.search("apple"))    # Output: True
print(trie.search("app"))      # Output: False
print(trie.starts_with("app")) # Output: True
trie.insert("app")
print(trie.search("app"))      # Output: True

8. Implement a Queue using Stacks

Implement a first in first out (FIFO) queue using only two stacks.

class MyQueue:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    
    def push(self, x):
        self.stack1.append(x)
    
    def pop(self):
        self.peek()
        return self.stack2.pop()
    
    def peek(self):
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2[-1]
    
    def empty(self):
        return not self.stack1 and not self.stack2

# Example usage
queue = MyQueue()
queue.push(1)
queue.push(2)
print(queue.peek())  # Output: 1
print(queue.pop())   # Output: 1
print(queue.empty()) # Output: False

9. Find the Kth Largest Element in an Array

Given an unsorted array, find the kth largest element in it.

import heapq

def find_kth_largest(nums, k):
    return heapq.nlargest(k, nums)[-1]

# Example usage
print(find_kth_largest([3, 2, 1, 5, 6, 4], 2))  # Output: 5
print(find_kth_largest([3, 2, 3, 1, 2, 4, 5, 5, 6], 4))  # Output: 4

10. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s.

def longest_palindrome(s):
    if not s:
        return ""
    
    start = 0
    max_length = 1
    
    for i in range(len(s)):
        # Check for odd-length palindromes
        left, right = i, i
        while left >= 0 and right < len(s) and s[left] == s[right]:
            if right - left + 1 > max_length:
                start = left
                max_length = right - left + 1
            left -= 1
            right += 1
        
        # Check for even-length palindromes
        left, right = i, i + 1
        while left >= 0 and right < len(s) and s[left] == s[right]:
            if right - left + 1 > max_length:
                start = left
                max_length = right - left + 1
            left -= 1
            right += 1
    
    return s[start:start + max_length]

# Example usage
print(longest_palindrome("babad"))  # Output: "bab" or "aba"
print(longest_palindrome("cbbd"))   # Output: "bb"

11. Implement a LRU Cache

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache = OrderedDict()
    
    def get(self, key):
        if key not in self.cache:
            return -1
        self.cache.move_to_end(key)
        return self.cache[key]
    
    def put(self, key, value):
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False)

# Example usage
cache = LRUCache(2)
cache.put(1, 1)
cache.put(2, 2)
print(cache.get(1))    # Output: 1
cache.put(3, 3)
print(cache.get(2))    # Output: -1
cache.put(4, 4)
print(cache.get(1))    # Output: -1
print(cache.get(3))    # Output: 3
print(cache.get(4))    # Output: 4

12. Implement a Min Stack

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    
    def push(self, val):
        self.stack.append(val)
        if not self.min_stack or val <= self.min_stack[-1]:
            self.min_stack.append(val)
    
    def pop(self):
        if self.stack.pop() == self.min_stack[-1]:
            self.min_stack.pop()
    
    def top(self):
        return self.stack[-1]
    
    def get_min(self):
        return self.min_stack[-1]

# Example usage
min_stack = MinStack()
min_stack.push(-2)
min_stack.push(0)
min_stack.push(-3)
print(min_stack.get_min())  # Output: -3
min_stack.pop()
print(min_stack.top())      # Output: 0
print(min_stack.get_min())  # Output: -2

13. Rotate Image

You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise).

def rotate_image(matrix):
    n = len(matrix)
    
    # Transpose the matrix
    for i in range(n):
        for j in range(i, n):
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
    
    # Reverse each row
    for i in range(n):
        matrix[i].reverse()

# Example usage
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
rotate_image(matrix)
print(matrix)
# Output: [[7, 4, 1], [8, 5, 2], [9, 6, 3]]

14. Serialize and Deserialize Binary Tree

Design an algorithm to serialize and deserialize a binary tree.

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Codec:
    def serialize(self, root):
        if not root:
            return "null"
        return f"{root.val},{self.serialize(root.left)},{self.serialize(root.right)}"
    
    def deserialize(self, data):
        def dfs():
            val = next(values)
            if val == "null":
                return None
            node = TreeNode(int(val))
            node.left = dfs()
            node.right = dfs()
            return node
        
        values = iter(data.split(","))
        return dfs()

# Example usage
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.right.left = TreeNode(4)
root.right.right = TreeNode(5)

codec = Codec()
serialized = codec.serialize(root)
print(serialized)  # Output: 1,2,null,null,3,4,null,null,5,null,null
deserialized = codec.deserialize(serialized)
print(codec.serialize(deserialized))  # Output: 1,2,null,null,3,4,null,null,5,null,null

15. Word Break

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

def word_break(s, word_dict):
    n = len(s)
    dp = [False] * (n + 1)
    dp[0] = True
    
    for i in range(1, n + 1):
        for j in range(i):
            if dp[j] and s[j:i] in word_dict:
                dp[i] = True
                break
    
    return dp[n]

# Example usage
print(word_break("leetcode", ["leet", "code"]))  # Output: True
print(word_break("applepenapple", ["apple", "pen"]))  # Output: True
print(word_break("catsandog", ["cats", "dog", "sand", "and", "cat"]))  # Output: False

16. Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

def merge_intervals(intervals):
    intervals.sort(key=lambda x: x[0])
    merged = []
    
    for interval in intervals:
        if not merged or merged[-1][1] < interval[0]:
            merged.append(interval)
        else:
            merged[-1][1] = max(merged[-1][1], interval[1])
    
    return merged

# Example usage
print(merge_intervals([[1,3],[2,6],[8,10],[15,18]]))  # Output: [[1,6],[8,10],[15,18]]
print(merge_intervals([[1,4],[4,5]]))  # Output: [[1,5]]

17. Implement strStr()

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

def str_str(haystack, needle):
    if not needle:
        return 0
    
    for i in range(len(haystack) - len(needle) + 1):
        if haystack[i:i+len(needle)] == needle:
            return i
    
    return -1

# Example usage
print(str_str("hello", "ll"))  # Output: 2
print(str_str("aaaaa", "bba"))  # Output: -1

18. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.

def length_of_longest_substring(s):
    char_index = {}
    max_length = 0
    start = 0
    
    for i, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        else:
            max_length = max(max_length, i - start + 1)
        char_index[char] = i
    
    return max_length

# Example usage
print(length_of_longest_substring("abcabcbb"))  # Output: 3
print(length_of_longest_substring("bbbbb"))  # Output: 1
print(length_of_longest_substring("pwwkew"))  # Output: 3

19. Minimum Window Substring

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

from collections import Counter

def min_window(s, t):
    if not t or not s:
        return ""

    dict_t = Counter(t)
    required = len(dict_t)

    left = 0
    right = 0
    formed = 0
    window_counts = {}

    ans = float("inf"), None, None

    while right < len(s):
        character = s[right]
        window_counts[character] = window_counts.get(character, 0) + 1

        if character in dict_t and window_counts[character] == dict_t[character]:
            formed += 1

        while left <= right and formed == required:
            character = s[left]

            if right - left + 1 < ans[0]:
                ans = (right - left + 1, left, right)

            window_counts[character] -= 1
            if character in dict_t and window_counts[character] < dict_t[character]:
                formed -= 1

            left += 1

        right += 1

    return "" if ans[0] == float("inf") else s[ans[1] : ans[2] + 1]

# Example usage
print(min_window("ADOBECODEBANC", "ABC"))  # Output: "BANC"
print(min_window("a", "a"))  # Output: "a"

20. Median of Two Sorted Arrays

Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.

def find_median_sorted_arrays(nums1, nums2):
    if len(nums1) > len(nums2):
        nums1, nums2 = nums2, nums1
    
    m, n = len(nums1), len(nums2)
    left, right = 0, m
    
    while left <= right:
        partition_x = (left + right) // 2
        partition_y = (m + n + 1) // 2 - partition_x
        
        max_left_x = float('-inf') if partition_x == 0 else nums1[partition_x - 1]
        min_right_x = float('inf') if partition_x == m else nums1[partition_x]
        
        max_left_y = float('-inf') if partition_y == 0 else nums2[partition_y - 1]
        min_right_y = float('inf') if partition_y == n else nums2[partition_y]
        
        if max_left_x <= min_right_y and max_left_y <= min_right_x:
            if (m + n) % 2 == 0:
                return (max(max_left_x, max_left_y) + min(min_right_x, min_right_y)) / 2
            else:
                return max(max_left_x, max_left_y)
        elif max_left_x > min_right_y:
            right = partition_x - 1
        else:
            left = partition_x + 1

# Example usage
print(find_median_sorted_arrays([1, 3], [2]))  # Output: 2.0
print(find_median_sorted_arrays([1, 2], [3, 4]))  # Output: 2.5

Tips for Succeeding in Coding Interviews

Now that we’ve covered the most common coding interview questions, here are some tips to help you succeed in your next technical interview:

  1. Practice regularly: Solve coding problems on platforms like LeetCode, HackerRank, or CodeSignal to improve your problem-solving skills.
  2. Understand the fundamentals: Make sure you have a solid grasp of data structures, algorithms, and time/space complexity analysis.
  3. Communicate your thought process: Explain your approach and reasoning while solving problems during the interview.
  4. Ask clarifying questions: Ensure you fully understand the problem before diving into the solution.
  5. Consider edge cases: Think about potential edge cases and handle them in your solution.
  6. Optimize your solution: After implementing a working solution, consider ways to optimize it for better time or space complexity.
  7. Test your code: Write test cases and walk through your code to catch any bugs or errors.
  8. Learn from your mistakes: Review and understand the solutions to problems you couldn’t solve, and try to implement them on your own later.
  9. Stay calm and focused: Remember that interviewers are interested in your problem-solving process, not just the final answer.
  10. Practice mock interviews: Conduct mock interviews with friends or use online platforms to simulate real interview conditions.

Conclusion

Mastering these common coding interview questions and following the tips provided will significantly improve your chances of success in technical interviews. Remember that consistent practice and a solid understanding of fundamental concepts are key to performing well in coding interviews.

As you prepare for your interviews, consider using resources like AlgoCademy to enhance your coding skills and gain confidence in tackling complex problems. With dedication and the right approach, you’ll be well-equipped to ace your next coding interview and land your dream job in the tech industry.