Back to Blog
Data Structures
15 min read

Data Structure Interview Questions: From Basic to Advanced with Solutions

Master essential data structure concepts with our comprehensive guide. From implementing a balanced binary tree to solving complex graph problems, learn the patterns and techniques that top companies are looking for in technical interviews.

Sarah Chen

Sarah Chen

Senior Software Engineerยท
2025-02-04
Data Structure Interview Questions: From Basic to Advanced with Solutions

Ever wondered why some developers breeze through technical interviews while others stumble? Often, it comes down to one thing: a solid understanding of data structures. Let's dive into the most important concepts you need to know, with real Java implementations that will impress your interviewers.

Essential Data Structures Every Developer Must Master

1. Custom ArrayList Implementation

Here's a question that separates good candidates from great ones: "Implement your own ArrayList." Let's build one that will make interviewers take notice:

public class CustomArrayList {
    private static final int INITIAL_CAPACITY = 10;
    private Object[] elements;
    private int size;
    
    public CustomArrayList() {
        elements = new Object[INITIAL_CAPACITY];
        size = 0;
    }
    
    @SuppressWarnings("unchecked")
    public T get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return (T) elements[index];
    }
    
    public void add(T element) {
        if (size == elements.length) {
            // Double the capacity when full
            int newCapacity = elements.length * 2;
            elements = Arrays.copyOf(elements, newCapacity);
        }
        elements[size++] = element;
    }
    
    public T remove(int index) {
        T removedElement = get(index);
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(elements, index + 1, elements, index, numMoved);
        }
        elements[--size] = null; // Help GC
        return removedElement;
    }
}

Key points that will impress interviewers:

  • Dynamic resizing with capacity doubling
  • Proper generic type handling
  • Null element consideration
  • Memory leak prevention

2. Implementing a Thread-Safe LRU Cache

A favorite among FAANG companies - implementing an LRU cache with thread safety:

public class LRUCache {
    private class Node {
        K key;
        V value;
        Node prev;
        Node next;
        
        Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }
    
    private final int capacity;
    private final Map cache;
    private final ReentrantReadWriteLock lock;
    private Node head;
    private Node tail;
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new HashMap<>();
        this.lock = new ReentrantReadWriteLock();
        this.head = new Node(null, null);
        this.tail = new Node(null, null);
        head.next = tail;
        tail.prev = head;
    }
    
    public V get(K key) {
        lock.readLock().lock();
        try {
            Node node = cache.get(key);
            if (node == null) {
                return null;
            }
            // Move to front
            moveToFront(node);
            return node.value;
        } finally {
            lock.readLock().unlock();
        }
    }
    
    public void put(K key, V value) {
        lock.writeLock().lock();
        try {
            Node node = cache.get(key);
            if (node != null) {
                node.value = value;
                moveToFront(node);
            } else {
                node = new Node(key, value);
                cache.put(key, node);
                addToFront(node);
                
                if (cache.size() > capacity) {
                    removeLRU();
                }
            }
        } finally {
            lock.writeLock().unlock();
        }
    }
    
    private void moveToFront(Node node) {
        removeNode(node);
        addToFront(node);
    }
    
    private void addToFront(Node node) {
        node.next = head.next;
        node.prev = head;
        head.next.prev = node;
        head.next = node;
    }
    
    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    
    private void removeLRU() {
        Node lru = tail.prev;
        removeNode(lru);
        cache.remove(lru.key);
    }
}

Watch your interviewer's eyes light up when you mention:

  • Thread safety with read-write locks
  • O(1) time complexity for operations
  • Memory-efficient doubly linked list
  • Clean handling of capacity constraints

3. Red-Black Tree Implementation

Here's a challenging one that shows deep understanding:

public class RedBlackTree> {
    private static final boolean RED = true;
    private static final boolean BLACK = false;
    
    private class Node {
        T value;
        Node left, right, parent;
        boolean color;
        
        Node(T value) {
            this.value = value;
            this.color = RED;
        }
    }
    
    private Node root;
    
    public void insert(T value) {
        Node node = new Node(value);
        if (root == null) {
            root = node;
        } else {
            Node parent = null;
            Node current = root;
            
            while (current != null) {
                parent = current;
                if (value.compareTo(current.value) < 0) {
                    current = current.left;
                } else {
                    current = current.right;
                }
            }
            
            node.parent = parent;
            if (value.compareTo(parent.value) < 0) {
                parent.left = node;
            } else {
                parent.right = node;
            }
        }
        
        fixAfterInsertion(node);
    }
    
    private void fixAfterInsertion(Node node) {
        node.color = RED;
        
        while (node != root && node.parent.color == RED) {
            if (node.parent == node.parent.parent.left) {
                Node uncle = node.parent.parent.right;
                
                if (uncle != null && uncle.color == RED) {
                    node.parent.color = BLACK;
                    uncle.color = BLACK;
                    node.parent.parent.color = RED;
                    node = node.parent.parent;
                } else {
                    if (node == node.parent.right) {
                        node = node.parent;
                        rotateLeft(node);
                    }
                    node.parent.color = BLACK;
                    node.parent.parent.color = RED;
                    rotateRight(node.parent.parent);
                }
            } else {
                // Symmetric case
                Node uncle = node.parent.parent.left;
                // Similar implementation...
            }
        }
        root.color = BLACK;
    }
    
    private void rotateLeft(Node node) {
        Node right = node.right;
        node.right = right.left;
        
        if (right.left != null) {
            right.left.parent = node;
        }
        right.parent = node.parent;
        
        if (node.parent == null) {
            root = right;
        } else if (node == node.parent.left) {
            node.parent.left = right;
        } else {
            node.parent.right = right;
        }
        
        right.left = node;
        node.parent = right;
    }
    
    private void rotateRight(Node node) {
        // Similar to rotateLeft, but mirrored
    }
}

Key points to discuss:

  • Self-balancing properties
  • Color property usage
  • Rotation operations
  • Time complexity guarantees

4. Graph Algorithm: Shortest Path with Multiple Conditions

A modern twist on Dijkstra's algorithm that often appears in system design interviews:

public class WeightedGraph {
    private class Edge {
        int to;
        int weight;
        Set conditions;
        
        Edge(int to, int weight, Set conditions) {
            this.to = to;
            this.weight = weight;
            this.conditions = conditions;
        }
    }
    
    private Map> graph;
    
    public int findShortestPath(int start, int end, Set userConditions) {
        PriorityQueue pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        Map distances = new HashMap<>();
        
        pq.offer(new int[]{start, 0});
        distances.put(start, 0);
        
        while (!pq.isEmpty()) {
            int[] current = pq.poll();
            int node = current[0];
            int distance = current[1];
            
            if (node == end) {
                return distance;
            }
            
            if (distance > distances.getOrDefault(node, Integer.MAX_VALUE)) {
                continue;
            }
            
            for (Edge edge : graph.getOrDefault(node, new ArrayList<>())) {
                if (edge.conditions.stream().allMatch(userConditions::contains)) {
                    int newDistance = distance + edge.weight;
                    if (newDistance < distances.getOrDefault(edge.to, Integer.MAX_VALUE)) {
                        distances.put(edge.to, newDistance);
                        pq.offer(new int[]{edge.to, newDistance});
                    }
                }
            }
        }
        
        return -1;
    }
}

Impressive points to highlight:

  • Conditional path finding
  • Efficient priority queue usage
  • Stream API for condition checking
  • Clean error handling

Ready to Test Your Knowledge?

We've only scratched the surface of what you need to know for technical interviews. Want to practice with more complex questions and get instant feedback?

Take the Data Structures Challenge โ†’

At QuizMaster, we've crafted hundreds of data structure challenges that:

  • Simulate real interview conditions
  • Provide detailed explanations
  • Offer step-by-step solutions
  • Track your progress

Don't just read about data structures - master them through practice!

Start Practicing Now โ†’

Remember: Understanding these concepts deeply isn't just about passing interviews - it's about becoming a better developer who can build more efficient, scalable systems.


P.S. The best developers practice regularly. Join thousands of others who've improved their interview success rate through QuizMaster's interactive challenges!