Data Structures Interview Guide
Data Structures Interview Guide
Table of Contents
1. Basic Concepts
2. Arrays
3. Linked Lists
4. Stacks
5. Queues
6. Trees
7. Hash Tables/HashMap
8. Graphs
9. Heaps
Basic Concepts
Arrays
6. What is an Array?
Answer: An array is a collection of elements of the same data type stored in contiguous memory
locations, accessed using indices.
Memory efficient
Simple to implement
Disadvantages:
java
// Using HashSet
findDuplicates((int
public static void findDuplicates int[[] arr
arr)) {
Set<
Set<Integer
Integer>
> seen = new HashSet
HashSet<
<>();
Set<
Set<Integer
Integer>
> duplicates = new HashSet
HashSet<
<>();
arr)) {
for (int num : arr
seen..add
if (!seen add((num
num))) {
duplicates..add
duplicates add((num
num));
}
}
System.
[Link].
[Link](
println("Duplicates: " + duplicates)
duplicates);
}
java
reverse((arr
reverse arr,, 0, k - 1);
reverse((arr
reverse arr,, kk,, n - 1);
reverse((arr
reverse arr,, 0, n - 1);
}
reverse((int
private static void reverse int[[] arr
arr,, int start
start,, int end
end)) {
end)) {
while (start < end
arr[[start
int temp = arr start]];
arr[[start
arr start]] = arr
arr[[end
end]];
arr[[end
arr end]] = temp
temp;;
start++
start++;;
end--
end--;;
}
}
Linked Lists
2. Doubly Linked List: Each node has pointers to both next and previous nodes
Dynamic size
Disadvantages:
java
fast..next != null
while (fast != null && fast null)) {
slow..next
slow = slow next;;
fast..next
fast = fast next..next
next;;
fast)) {
if (slow == fast
true;; // Cycle detected
return true
}
}
false;;
return false
}
15. How to reverse a linked list?
Answer:
java
// Iterative approach
reverseList((ListNode head
public ListNode reverseList head)) {
null;;
ListNode prev = null
head;;
ListNode current = head
null)) {
while (current != null
ListNode next = current.
[Link]
next;;
current..next = prev
current prev;;
current;;
prev = current
next;;
current = next
}
java
findMiddle((ListNode head
public ListNode findMiddle head)) {
head;;
ListNode slow = head
head;;
ListNode fast = head
fast..next != null
while (fast != null && fast null)) {
slow..next
slow = slow next;;
fast..next
fast = fast next..next
next;;
}
java
mergeTwoLists((ListNode l1
public ListNode mergeTwoLists l1,, ListNode l2
l2)) {
ListNode((0);
ListNode dummy = new ListNode
dummy;;
ListNode current = dummy
null)) {
while (l1 != null && l2 != null
l1..val <= l2
if (l1 l2..val
val)) {
current..next = l1
current l1;;
l1 = l1
l1..next
next;;
} else {
current..next = l2
current l2;;
l2 = l2.
[Link];
next;
}
current..next
current = current next;;
}
java
removeNthFromEnd((ListNode head
public ListNode removeNthFromEnd head,, int n
n)) {
ListNode dummy = new ListNode
ListNode((0);
dummy.
[Link] = head;
head;
dummy;;
ListNode first = dummy
dummy;;
ListNode second = dummy
java
class Stack {
int[[] stack
private int stack;;
top;;
private int top
capacity;;
private int capacity
Stack((int size
public Stack size)) {
int[[size
stack = new int size]];
size;;
capacity = size
top = -1;
}
push((int item
public void push item)) {
if (top == capacity - 1) {
RuntimeException(("Stack Overflow")
throw new RuntimeException Overflow");
}
stack[[++
stack ++top
top]] = item
item;;
}
pop(() {
public int pop
if (top == -1) {
RuntimeException(("Stack Underflow")
throw new RuntimeException Underflow");
}
stack[[top
return stack top--
--]];
}
isEmpty(() {
public boolean isEmpty
return top == -1;
}
}
java
class StackNode {
data;;
int data
next;;
StackNode next
StackNode((int data
StackNode data)) {
this..data = data
this data;;
}
}
class Stack {
top;;
private StackNode top
push((int data
public void push data)) {
StackNode((data
StackNode newNode = new StackNode data));
newNode..next = top
newNode top;;
newNode;;
top = newNode
}
peek(() {
public int peek
null)) {
if (top == null
RuntimeException(("Stack is empty")
throw new RuntimeException empty");
}
top..data
return top data;;
}
}
Undo operations
Browser back button
Syntax parsing
Backtracking algorithms
java
isBalanced((String ss)) {
public boolean isBalanced
Stack<
Stack<Character
Character>
> stack = new Stack
Stack<
<>();
stack..pop
char top = stack pop(();
'(')) ||
if ((c == ')' && top != '('
(c == '}' && top != '{'
'{')) ||
(c == ']' && top != '['
'['))) {
false;;
return false
}
}
}
stack..isEmpty
return stack isEmpty(();
}
Queues
Answer:
java
class Queue {
int[[] queue
private int queue;;
private int front,
front, rear,
rear, size,
size, capacity;
capacity;
Queue((int capacity
public Queue capacity)) {
this..capacity = capacity
this capacity;;
int[[capacity
queue = new int capacity]];
front = 0;
rear = -1;
size = 0;
}
enqueue((int item
public void enqueue item)) {
capacity)) {
if (size == capacity
RuntimeException(("Queue is full")
throw new RuntimeException full");
}
capacity;;
rear = (rear + 1) % capacity
queue[[rear
queue rear]] = item
item;;
size++
size++;;
}
dequeue(() {
public int dequeue
if (size == 0) {
RuntimeException(("Queue is empty")
throw new RuntimeException empty");
}
int item = queue[
queue[front]
front];
capacity;;
front = (front + 1) % capacity
size--
size--;;
item;;
return item
}
}
Trees
2. Complete Binary Tree: All levels filled except possibly last, filled left to right
3. Perfect Binary Tree: All internal nodes have 2 children, all leaves at same level
4. Balanced Binary Tree: Height difference between left and right subtrees ≤ 1
java
// Inorder Traversal
inorder((TreeNode root
public void inorder root)) {
null)) {
if (root != null
inorder((root
inorder root..left
left));
System..out
System out..print
print((root
root..val + " ")
");
inorder((root
inorder root..right
right));
}
}
queue..isEmpty
while (!queue isEmpty(()) {
queue..poll
TreeNode node = queue poll(();
System..out
System out..print
print((node
node..val + " ")
");
node..left != null
if (node null)) queue
queue..offer
offer((node
node..left
left));
node..right != null
if (node null)) queue
queue..offer
offer((node
node..right
right));
}
}
java
height((TreeNode root
public int height root)) {
null)) return -1; // or 0 depending on definition
if (root == null
return 1 + Math.
[Link](
max(height(
height(root.
[Link])
left), height(
height(root.
[Link])
right));
}
java
isBalanced((TreeNode root
public boolean isBalanced root)) {
return checkHeight(
checkHeight(root)
root) != -1;
}
checkHeight((TreeNode root
private int checkHeight root)) {
null)) return 0;
if (root == null
checkHeight((root
int leftHeight = checkHeight root..left
left));
if (leftHeight == -1) return -1;
checkHeight((root
int rightHeight = checkHeight root..right
right));
if (rightHeight == -1) return -1;
Math..abs
if (Math abs((leftHeight - rightHeight
rightHeight)) > 1) {
return -1; // Not balanced
}
Math..max
return Math max((leftHeight
leftHeight,, rightHeight
rightHeight)) + 1;
}
Is deterministic
Is fast to compute
Double Hashing
HashMap HashTable
java
class MyHashMap {
private static class Node {
key,, value
int key value;;
next;;
Node next
Node((int key
Node key,, int value
value)) {
this..key = key
this key;;
this..value = value
this value;;
}
}
private Node[
Node[] buckets;
buckets;
16;;
private int capacity = 16
MyHashMap(() {
public MyHashMap
Node[[capacity
buckets = new Node capacity]];
}
put((int key
public void put key,, int value
value)) {
hash((key
int index = hash key));
buckets[[index
Node head = buckets index]];
get((int key
public int get key)) {
hash((key
int index = hash key));
buckets[[index
Node current = buckets index]];
null)) {
while (current != null
current..key == key
if (current key)) {
current..value
return current value;;
}
current..next
current = current next;;
}
Graphs
1. Directed vs Undirected
2. Weighted vs Unweighted
3. Connected vs Disconnected
4. Cyclic vs Acyclic
5. Simple vs Multigraph
java
dfs((int vertex
public void dfs vertex,, boolean
boolean[[] visited
visited,, List
List<
<List
List<
<Integer
Integer>
>> adj
adj)) {
visited[[vertex
visited vertex]] = true
true;;
System..out
System out..print
print((vertex + " ")
");
adj..get
for (int neighbor : adj get((vertex
vertex))) {
visited[[neighbor
if (!visited neighbor]]) {
dfs((neighbor
dfs neighbor,, visited
visited,, adj
adj));
}
}
}
java
bfs((int start
public void bfs start,, List
List<
<List
List<
<Integer
Integer>
>> adj
adj)) {
boolean[[] visited = new boolean
boolean boolean[[adj
adj..size
size(()];
Queue<
Queue<Integer
Integer>
> queue = new LinkedList
LinkedList<
<>();
visited[[start
visited start]] = true
true;;
queue..offer
queue offer((start
start));
queue..isEmpty
while (!queue isEmpty(()) {
queue..poll
int vertex = queue poll(();
System..out
System out..print
print((vertex + " ")
");
adj..get
for (int neighbor : adj get((vertex
vertex))) {
visited[[neighbor
if (!visited neighbor]]) {
visited[[neighbor
visited neighbor]] = true
true;;
queue..offer
queue offer((neighbor
neighbor));
}
}
}
}
Heaps
java
class MinHeap {
int[[] heap
private int heap;;
size;;
private int size
capacity;;
private int capacity
MinHeap((int capacity
public MinHeap capacity)) {
this..capacity = capacity
this capacity;;
int[[capacity
heap = new int capacity]];
size = 0;
}
insert((int value
public void insert value)) {
capacity)) {
if (size == capacity
RuntimeException(("Heap is full")
throw new RuntimeException full");
}
// Insert at end
heap[[size
heap size]] = value
value;;
size++
size++;;
// Heapify up
heapifyUp((size - 1);
heapifyUp
}
heapifyUp((int index
private void heapifyUp index)) {
heap[[parent
while (index > 0 && heap parent((index
index))] > heap
heap[[index
index]]) {
swap((index
swap index,, parent
parent((index
index)));
parent((index
index = parent index));
}
}
extractMin(() {
public int extractMin
if (size == 0) {
RuntimeException(("Heap is empty")
throw new RuntimeException empty");
}
heap[[0];
int min = heap
heap[
heap[0] = heap[
heap[size - 1];
size--
size--;;
heapifyDown((0);
heapifyDown
min;;
return min
}
heapifyDown((int index
private void heapifyDown index)) {
index;;
int smallest = index
leftChild((index
int left = leftChild index));
rightChild((index
int right = rightChild index));
heap[[left
if (left < size && heap left]] < heap
heap[[smallest
smallest]]) {
left;;
smallest = left
}
if (right < size && heap[
heap[right]
right] < heap[
heap[smallest]
smallest]) {
right;;
smallest = right
}
index)) {
if (smallest != index
swap((index
swap index,, smallest
smallest));
heapifyDown((smallest
heapifyDown smallest));
}
}
java
class TrieNode {
TrieNode[[] children = new TrieNode
TrieNode TrieNode[[26
26]];
false;;
boolean isEndOfWord = false
}
class Trie {
root;;
private TrieNode root
Trie(() {
public Trie
TrieNode(();
root = new TrieNode
}
insert((String word
public void insert word)) {
root;;
TrieNode current = root
word..toCharArray
for (char c : word toCharArray(()) {
'a';;
int index = c - 'a'
current..children
if (current children[[index
index]] == null
null)) {
current..children
current children[[index
index]] = new TrieNode
TrieNode(();
}
current = current.
[Link][
children[index]
index];
}
current..isEndOfWord = true
current true;;
}
search((String word
public boolean search word)) {
root;;
TrieNode current = root
for (char c : word.
[Link](
toCharArray()) {
'a';;
int index = c - 'a'
current..children
if (current children[[index
index]] == null
null)) {
false;;
return false
}
current..children
current = current children[[index
index]];
}
current..isEndOfWord
return current isEndOfWord;;
}
}
Merge Sort O(n log n) O(n log n) O(n log n) O(n) Yes
java
binarySearch((int
public int binarySearch int[[] arr
arr,, int target
target)) {
arr..length - 1;
int left = 0, right = arr
right)) {
while (left <= right
left)) / 2;
int mid = left + (right - left
arr[[mid
if (arr mid]] == target
target)) {
mid;;
return mid
arr[[mid
} else if (arr mid]] < target
target)) {
left = mid + 1;
} else {
right = mid - 1;
}
}
java
int[[] intersection
public int intersection((int
int[[] nums1
nums1,, int
int[[] nums2
nums2)) {
Set<
Set<Integer
Integer>
> set1 = new HashSet
HashSet<
<>();
nums1)) {
for (int num : nums1
set1..add
set1 add((num
num));
}
Set<
Set<Integer
Integer>
> result = new HashSet
HashSet<
<>();
nums2)) {
for (int num : nums2
set1..contains
if (set1 contains((num
num))) {
result..add
result add((num
num));
}
}
result..stream
return result stream(().mapToInt
mapToInt((Integer
Integer::::intValue
intValue)).toArray
toArray(();
}
java
class LRUCache {
Map<
private Map<Integer
Integer,, Node
Node>
> cache
cache;;
capacity;;
private int capacity
head,, tail
private Node head tail;;
class Node {
key,, value
int key value;;
prev,, next
Node prev next;;
Node((int key
Node key,, int value
value)) {
this..key = key
this key;;
this.
[Link] = value;
value;
}
}
LRUCache((int capacity
public LRUCache capacity)) {
this..capacity = capacity
this capacity;;
HashMap<
cache = new HashMap<>();
head = new Node(
Node(0, 0);
tail = new Node(
Node(0, 0);
head..next = tail
head tail;;
tail..prev = head
tail head;;
}
get((int key
public int get key)) {
cache..get
Node node = cache get((key
key));
if (node == null)
null) return -1;
moveToHead((node
moveToHead node));
node..value
return node value;;
}
put((int key
public void put key,, int value
value)) {
cache..get
Node node = cache get((key
key));
null)) {
if (node == null
Node((key
Node newNode = new Node key,, value
value));
cache..put
cache put((key
key,, newNode
newNode));
addToHead((newNode
addToHead newNode));
cache..size
if (cache size(() > capacity
capacity)) {
Node tail = removeTail(
removeTail();
cache..remove
cache remove((tail
tail..key
key));
}
} else {
node..value = value
node value;;
moveToHead((node
moveToHead node));
}
}
addToHead((Node node
private void addToHead node)) {
node..prev = head
node head;;
node..next = head
node head..next
next;;
head..next
head next..prev = node
node;;
head..next = node
head node;;
}
removeNode((Node node
private void removeNode node)) {
node..prev
node prev..next = node
node..next
next;;
node..next
node next..prev = node
node..prev
prev;;
}
moveToHead((Node node
private void moveToHead node)) {
removeNode((node
removeNode node));
addToHead(
addToHead(node)
node);
}
removeTail(() {
private Node removeTail
tail..prev
Node lastNode = tail prev;;
removeNode((lastNode
removeNode lastNode));
lastNode;;
return lastNode
}
}
java
maxSubArray((int
public int maxSubArray int[[] nums
nums)) {
nums[[0];
int maxSoFar = nums
nums[[0];
int maxEndingHere = nums
nums..length
for (int i = 1; i < nums length;; ii++
++)) {
Math..max
maxEndingHere = Math max((nums
nums[[i], maxEndingHere + nums
nums[[i]);
Math..max
maxSoFar = Math max((maxSoFar
maxSoFar,, maxEndingHere
maxEndingHere));
}
maxSoFar;;
return maxSoFar
}
java
class MyStack {
Queue<
private Queue<Integer
Integer>
> q1 = new LinkedList
LinkedList<
<>();
Queue<
private Queue<Integer
Integer>
> q2 = new LinkedList
LinkedList<
<>();
push((int xx)) {
public void push
q2..offer
q2 offer((x);
q1..isEmpty
while (!q1 isEmpty(()) {
q2..offer
q2 offer((q1
q1..poll
poll(());
}
Queue<
Queue<Integer
Integer>
> temp = q1
q1;;
q1 = q2;
q2;
temp;;
q2 = temp
}
pop(() {
public int pop
q1..poll
return q1 poll(();
}
top(() {
public int top
q1..peek
return q1 peek(();
}
empty(() {
public boolean empty
q1..isEmpty
return q1 isEmpty(();
}
}
java
class MyQueue {
Stack<
private Stack<Integer
Integer>
> input = new Stack
Stack<
<>();
private Stack<
Stack<Integer>
Integer> output = new Stack<
Stack<>();
push((int xx)) {
public void push
input..push
input push((x);
}
pop(() {
public int pop
peek(();
peek
return output.
[Link](
pop();
}
peek(() {
public int peek
output..empty
if (output empty(()) {
input..empty
while (!input empty(()) {
output..push
output push((input
input..pop
pop(());
}
}
output..peek
return output peek(();
}
empty(() {
public boolean empty
input..empty
return input empty(() && output
output..empty
empty(();
}
}
java
// Using Min Heap
findKthLargest((int
public int findKthLargest int[[] nums
nums,, int kk)) {
PriorityQueue<
PriorityQueue<Integer
Integer>
> minHeap = new PriorityQueue
PriorityQueue<
<>();
nums)) {
for (int num : nums
minHeap..offer
minHeap offer((num
num));
minHeap..size
if (minHeap size(() > kk)) {
minHeap..poll
minHeap poll(();
}
}
return minHeap.
[Link](
peek();
}
java
sortColors((int
public void sortColors int[[] nums
nums)) {
int low = 0, mid = 0, high = nums.
[Link] - 1;
high)) {
while (mid <= high
nums[[mid
if (nums mid]] == 0) {
swap((nums
swap nums,, low
low++
++,, mid
mid++
++));
nums[[mid
} else if (nums mid]] == 1) {
mid++
mid++;;
} else {
swap(
swap(nums,
nums, mid,
mid, high--
high--));
}
}
}
java
detectAndRemoveCycle((ListNode head
public ListNode detectAndRemoveCycle head)) {
head..next == null
if (head == null || head null)) return head
head;;
// Detect cycle
fast..next != null
while (fast != null && fast null)) {
slow = slow.
[Link];
next;
fast..next
fast = fast next..next
next;;
fast)) break
if (slow == fast break;;
}
fast..next == null
if (fast == null || fast null)) return head
head;; // No cycle
// Remove cycle
while (fast.
[Link] != slow)
slow) {
fast..next
fast = fast next;;
}
fast..next = null
fast null;;
head;;
return head
}
java
count)) {
for (int c : count
false;;
if (c != 0) return false
}
true;;
return true
}
87. What is the best way to find duplicates in array?
Answer:
java
nums)) {
for (int num : nums
seen..add
if (!seen add((num
num))) {
duplicates..add
duplicates add((num
num));
}
}
duplicates;;
return duplicates
}
nums..length
for (int i = 0; i < nums length;; ii++
++)) {
Math..abs
int index = Math abs((nums
nums[[i]) - 1;
nums[[index
if (nums index]] < 0) {
result..add
result add((Math
Math..abs
abs((nums
nums[[i]));
} else {
nums[[index
nums index]] = -nums
nums[[index
index]];
}
}
result;;
return result
}
java
class LFUCache {
Map<
private Map<Integer
Integer,, Integer
Integer>
> values
values;;
Map<
private Map<Integer
Integer,, Integer
Integer>
> frequencies
frequencies;;
Map<
private Map<Integer
Integer,, LinkedHashSet
LinkedHashSet<
<Integer
Integer>
>> frequencyGroups
frequencyGroups;;
capacity;;
private int capacity
minFrequency;;
private int minFrequency
LFUCache((int capacity
public LFUCache capacity)) {
this..capacity = capacity
this capacity;;
HashMap<
values = new HashMap<>();
HashMap<
frequencies = new HashMap<>();
frequencyGroups = new HashMap<
HashMap<>();
minFrequency = 1;
}
get((int key
public int get key)) {
values..containsKey
if (!values containsKey((key
key))) return -1;
updateFrequency(
updateFrequency(key)
key);
return values.
[Link](
get(key)
key);
}
put((int key
public void put key,, int value
value)) {
return;;
if (capacity <= 0) return
values..containsKey
if (values containsKey((key
key))) {
values.
[Link](
put(key,
key, value)
value);
updateFrequency((key
updateFrequency key));
return;;
return
}
values..size
if (values size(() >= capacity
capacity)) {
evictLFU(();
evictLFU
}
values..put
values put((key
key,, value
value));
frequencies..put
frequencies put((key
key,, 1);
frequencyGroups..computeIfAbsent
frequencyGroups computeIfAbsent((1, k -> new LinkedHashSet
LinkedHashSet<
<>()).add
add((key
key));
minFrequency = 1;
}
frequencyGroups..get
frequencyGroups get((freq
freq)).remove
remove((key
key));
frequencyGroups..get
if (freq == minFrequency && frequencyGroups get((freq
freq)).isEmpty
isEmpty(()) {
minFrequency++
minFrequency++;;
}
frequencyGroups..computeIfAbsent
frequencyGroups computeIfAbsent((freq + 1, k -> new LinkedHashSet
LinkedHashSet<
<>()).add
add((key
key));
}
evictLFU(() {
private void evictLFU
frequencyGroups..get
int keyToEvict = frequencyGroups get((minFrequency
minFrequency)).iterator
iterator(().next
next(();
frequencyGroups..get
frequencyGroups get((minFrequency
minFrequency)).remove
remove((keyToEvict
keyToEvict));
values.
[Link](
remove(keyToEvict)
keyToEvict);
frequencies..remove
frequencies remove((keyToEvict
keyToEvict));