Java Data Structures Quick Reference for LeetCode - Complete Cheat Sheet
Master essential Java data structures for coding interviews with this comprehensive guide covering Queue, Stack, List, Set, Map, Heap, String, and Array utilities. Includes method signatures, time complexity, and LeetCode patterns from 11-year FAANG veteran.
Introduction: Your Interview Swiss Army Knife
When solving LeetCode problems in Java, knowing which data structure to use and which methods are available can make the difference between a quick solve and getting stuck for 30 minutes.
This guide is your quick reference cheat sheet for the most common Java data structures used in coding interviews. After 11+ years at Microsoft, Booking.com, and Alibaba, I’ve distilled the essential operations you’ll reach for again and again.
How to Use This Guide
- During prep: Read through each section to familiarize yourself with available methods
- During practice: Keep this open as a quick lookup reference
- Before interviews: Review the time complexity tables to avoid performance pitfalls
Java Version Notes
- This guide covers Java 8+ features
- All code examples are interview-ready (no external dependencies)
- Focus on
java.util.*package (standard library)
1. Queue & Stack Operations
ArrayDeque (Recommended for Stacks & Queues)
ArrayDeque is the modern, preferred implementation for both queue and stack operations. It’s faster than LinkedList and Stack.
As a Queue (FIFO)
Deque<Integer> queue = new ArrayDeque<>();
// Add elements (back of queue)
queue.offer(1); // Returns boolean, O(1)
queue.add(2); // Throws exception on failure, O(1)
// Remove elements (front of queue)
Integer val = queue.poll(); // Returns null if empty, O(1)
Integer val = queue.remove(); // Throws exception if empty, O(1)
// Peek (don't remove)
Integer val = queue.peek(); // Returns null if empty, O(1)
Integer val = queue.element(); // Throws exception if empty, O(1)
// Size
int size = queue.size(); // O(1)
boolean empty = queue.isEmpty(); // O(1)
As a Stack (LIFO)
Deque<Integer> stack = new ArrayDeque<>();
// Push (add to top)
stack.push(1); // O(1)
// Pop (remove from top)
Integer val = stack.pop(); // Throws exception if empty, O(1)
// Peek (don't remove)
Integer val = stack.peek(); // Returns null if empty, O(1)
// Size
int size = stack.size(); // O(1)
boolean empty = stack.isEmpty(); // O(1)
As a Deque (Double-Ended Queue)
Deque<Integer> deque = new ArrayDeque<>();
// Add to front
deque.offerFirst(1); // O(1)
deque.addFirst(2); // O(1)
// Add to back
deque.offerLast(3); // O(1)
deque.addLast(4); // O(1)
// Remove from front
Integer val = deque.pollFirst(); // O(1)
Integer val = deque.removeFirst(); // O(1)
// Remove from back
Integer val = deque.pollLast(); // O(1)
Integer val = deque.removeLast(); // O(1)
// Peek
Integer front = deque.peekFirst(); // O(1)
Integer back = deque.peekLast(); // O(1)
Stack (Legacy - Avoid in Interviews)
Stack<Integer> stack = new Stack<>();
stack.push(1); // O(1)
Integer val = stack.pop(); // O(1)
Integer val = stack.peek(); // O(1)
boolean empty = stack.empty(); // O(1)
int pos = stack.search(1); // O(n), returns 1-based position
⚠️ Interview Tip: Prefer
ArrayDequeoverStack. Interviewers may comment thatStackis legacy code.
Comparison Table
| Operation | ArrayDeque (Queue) | ArrayDeque (Stack) | LinkedList | Stack (Legacy) |
|---|---|---|---|---|
| Add/Push | offer() O(1) | push() O(1) | offer() O(1) | push() O(1) |
| Remove/Pop | poll() O(1) | pop() O(1) | poll() O(1) | pop() O(1) |
| Peek | peek() O(1) | peek() O(1) | peek() O(1) | peek() O(1) |
| Speed | ⚡ Fastest | ⚡ Fastest | Slower | Slower |
Common LeetCode Patterns
Monotonic Stack: Track next greater/smaller element
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < nums.length; i++) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
int idx = stack.pop();
// Process...
}
stack.push(i);
}
Sliding Window Maximum: Use deque to maintain max in window
Deque<Integer> deque = new ArrayDeque<>(); // Store indices
2. List Operations
ArrayList (Dynamic Array)
Best for random access and sequential iteration.
List<Integer> list = new ArrayList<>();
// Add elements
list.add(1); // Add to end, O(1) amortized
list.add(0, 10); // Insert at index, O(n)
// Access elements
int val = list.get(0); // O(1)
list.set(0, 20); // O(1)
// Remove elements
list.remove(0); // Remove by index, O(n)
list.remove(Integer.valueOf(10)); // Remove by value, O(n)
// Search
boolean exists = list.contains(10); // O(n)
int index = list.indexOf(10); // O(n), returns -1 if not found
int lastIdx = list.lastIndexOf(10); // O(n)
// Size
int size = list.size(); // O(1)
boolean empty = list.isEmpty(); // O(1)
list.clear(); // O(n)
// Sorting
Collections.sort(list); // O(n log n)
Collections.sort(list, Collections.reverseOrder()); // Descending
// Conversion
int[] arr = list.stream().mapToInt(i -> i).toArray(); // To array
LinkedList (Doubly-Linked List)
Best for frequent insertions/deletions at both ends.
LinkedList<Integer> list = new LinkedList<>();
// Add at ends
list.addFirst(1); // O(1)
list.addLast(2); // O(1)
// Remove from ends
Integer first = list.removeFirst(); // O(1)
Integer last = list.removeLast(); // O(1)
// Peek (don't remove)
Integer first = list.peekFirst(); // O(1), returns null if empty
Integer last = list.peekLast(); // O(1)
// Access (slow!)
int val = list.get(0); // O(n) - avoid this!
Comparison Table
| Operation | ArrayList | LinkedList |
|---|---|---|
| Access by index | O(1) | O(n) ❌ |
| Add/Remove at end | O(1) | O(1) |
| Add/Remove at beginning | O(n) | O(1) ✅ |
| Add/Remove at middle | O(n) | O(n) |
| Memory overhead | Low | High (pointers) |
| Use case | Random access | Frequent head/tail ops |
Common LeetCode Patterns
Two Pointers:
int left = 0, right = list.size() - 1;
while (left < right) {
// Process...
left++;
right--;
}
Binary Search on Sorted List:
Collections.sort(list);
int idx = Collections.binarySearch(list, target); // O(log n)
// Returns index if found, or (-(insertion point) - 1) if not found
3. Set Operations
HashSet (Unordered)
Best for fast lookups when order doesn’t matter.
Set<Integer> set = new HashSet<>();
// Add elements
boolean added = set.add(1); // O(1), returns false if already exists
// Remove elements
boolean removed = set.remove(1); // O(1)
// Check existence
boolean exists = set.contains(1); // O(1)
// Size
int size = set.size(); // O(1)
boolean empty = set.isEmpty(); // O(1)
// Iteration
for (int val : set) {
// Unordered!
}
// Set operations
Set<Integer> set2 = new HashSet<>(Arrays.asList(2, 3, 4));
set.addAll(set2); // Union
set.retainAll(set2); // Intersection
set.removeAll(set2); // Difference
TreeSet (Sorted)
Best for maintaining sorted order and range queries.
TreeSet<Integer> set = new TreeSet<>();
// Add/Remove (same as HashSet but O(log n))
set.add(5); // O(log n)
set.remove(5); // O(log n)
boolean exists = set.contains(5); // O(log n)
// Sorted access
Integer first = set.first(); // O(log n), smallest element
Integer last = set.last(); // O(log n), largest element
// Range queries
Integer ceil = set.ceiling(4); // O(log n), smallest >= 4, null if none
Integer floor = set.floor(4); // O(log n), largest <= 4, null if none
Integer higher = set.higher(4); // O(log n), smallest > 4
Integer lower = set.lower(4); // O(log n), largest < 4
// Subset views
SortedSet<Integer> head = set.headSet(5); // Elements < 5
SortedSet<Integer> tail = set.tailSet(5); // Elements >= 5
SortedSet<Integer> sub = set.subSet(2, 8); // Elements [2, 8)
// Remove first/last
Integer first = set.pollFirst(); // O(log n), remove and return
Integer last = set.pollLast(); // O(log n)
LinkedHashSet (Insertion Order)
Maintains insertion order with HashSet performance.
Set<Integer> set = new LinkedHashSet<>();
// Same methods as HashSet, but iteration preserves insertion order
Comparison Table
| Operation | HashSet | TreeSet | LinkedHashSet |
|---|---|---|---|
| Add/Remove | O(1) ✅ | O(log n) | O(1) ✅ |
| Contains | O(1) ✅ | O(log n) | O(1) ✅ |
| Order | None | Sorted ✅ | Insertion ✅ |
| Range queries | ❌ | ✅ ceiling/floor | ❌ |
| Use case | Fast lookup | Sorted data | Preserve order |
Common LeetCode Patterns
Find Duplicates:
Set<Integer> seen = new HashSet<>();
for (int num : nums) {
if (!seen.add(num)) {
// Duplicate found!
}
}
Two Sum with Set:
Set<Integer> seen = new HashSet<>();
for (int num : nums) {
if (seen.contains(target - num)) {
return true;
}
seen.add(num);
}
4. Map Operations
HashMap (Unordered)
Best for fast key-value lookups when order doesn’t matter.
Map<String, Integer> map = new HashMap<>();
// Put elements
map.put("key", 1); // O(1), returns old value or null
map.putIfAbsent("key", 2); // O(1), only put if key doesn't exist
// Get elements
Integer val = map.get("key"); // O(1), returns null if not found
Integer val = map.getOrDefault("key", 0); // O(1), with default
// Check existence
boolean hasKey = map.containsKey("key"); // O(1)
boolean hasVal = map.containsValue(1); // O(n) - slow!
// Remove
Integer removed = map.remove("key"); // O(1), returns old value
// Size
int size = map.size(); // O(1)
boolean empty = map.isEmpty(); // O(1)
// Iteration (BEST PRACTICE)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
}
// Iterate keys only
for (String key : map.keySet()) {
// O(n)
}
// Iterate values only
for (Integer value : map.values()) {
// O(n)
}
// Compute methods (Java 8+)
map.merge("key", 1, Integer::sum); // Increment by 1
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
map.computeIfAbsent("key", k -> 0);
map.computeIfPresent("key", (k, v) -> v + 1);
TreeMap (Sorted by Keys)
Best for maintaining sorted key order and range queries.
TreeMap<Integer, String> map = new TreeMap<>();
// Basic operations (same as HashMap but O(log n))
map.put(5, "five"); // O(log n)
String val = map.get(5); // O(log n)
map.remove(5); // O(log n)
// Sorted access
Integer firstKey = map.firstKey(); // O(log n), smallest key
Integer lastKey = map.lastKey(); // O(log n), largest key
Map.Entry<Integer, String> firstEntry = map.firstEntry(); // O(log n)
Map.Entry<Integer, String> lastEntry = map.lastEntry(); // O(log n)
// Range queries
Integer ceilKey = map.ceilingKey(4); // O(log n), smallest key >= 4
Integer floorKey = map.floorKey(4); // O(log n), largest key <= 4
Integer higherKey = map.higherKey(4); // O(log n), smallest key > 4
Integer lowerKey = map.lowerKey(4); // O(log n), largest key < 4
Map.Entry<Integer, String> ceilEntry = map.ceilingEntry(4);
Map.Entry<Integer, String> floorEntry = map.floorEntry(4);
// Submap views
SortedMap<Integer, String> head = map.headMap(5); // Keys < 5
SortedMap<Integer, String> tail = map.tailMap(5); // Keys >= 5
SortedMap<Integer, String> sub = map.subMap(2, 8); // Keys [2, 8)
// Remove first/last
Map.Entry<Integer, String> first = map.pollFirstEntry(); // O(log n)
Map.Entry<Integer, String> last = map.pollLastEntry(); // O(log n)
LinkedHashMap (Insertion/Access Order)
Maintains insertion order or access order (useful for LRU Cache).
// Insertion order (default)
Map<Integer, String> map = new LinkedHashMap<>();
// Access order (for LRU Cache)
Map<Integer, String> lruMap = new LinkedHashMap<>(16, 0.75f, true);
// Parameters: initialCapacity, loadFactor, accessOrder=true
// Override removeEldestEntry for LRU eviction
Map<Integer, String> lruCache = new LinkedHashMap<Integer, String>(capacity, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
return size() > capacity;
}
};
Comparison Table
| Operation | HashMap | TreeMap | LinkedHashMap |
|---|---|---|---|
| Put/Get/Remove | O(1) ✅ | O(log n) | O(1) ✅ |
| Order | None | Sorted ✅ | Insertion/Access ✅ |
| Range queries | ❌ | ✅ ceiling/floor | ❌ |
| Use case | Fast lookup | Sorted keys | LRU cache |
Common LeetCode Patterns
Frequency Map:
Map<Character, Integer> freq = new HashMap<>();
for (char c : s.toCharArray()) {
freq.put(c, freq.getOrDefault(c, 0) + 1);
}
Sliding Window with Map:
Map<Character, Integer> window = new HashMap<>();
int left = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
window.put(c, window.getOrDefault(c, 0) + 1);
while (/* condition */) {
char d = s.charAt(left);
window.put(d, window.get(d) - 1);
if (window.get(d) == 0) window.remove(d);
left++;
}
}
5. Heap / PriorityQueue
PriorityQueue (Min Heap by Default)
Best for maintaining top K elements or processing in priority order.
// Min heap (default)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// Max heap (reverse order)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
// Custom comparator
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
// Add elements
pq.offer(5); // O(log n), returns boolean
pq.add(3); // O(log n), throws exception on failure
// Remove elements
Integer min = pq.poll(); // O(log n), returns null if empty
Integer min = pq.remove(); // O(log n), throws exception if empty
// Peek (don't remove)
Integer min = pq.peek(); // O(1), returns null if empty
Integer min = pq.element(); // O(1), throws exception if empty
// Size
int size = pq.size(); // O(1)
boolean empty = pq.isEmpty(); // O(1)
// Remove specific element (slow!)
pq.remove(5); // O(n) - avoid if possible!
// Contains (slow!)
boolean exists = pq.contains(5); // O(n) - avoid!
Custom Comparators
// Compare by first element of array
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
// Compare by custom object field
class Task {
int priority;
String name;
}
PriorityQueue<Task> pq = new PriorityQueue<>((a, b) -> a.priority - b.priority);
// Multiple criteria
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
if (a[0] != b[0]) return a[0] - b[0]; // First by a[0]
return a[1] - b[1]; // Then by a[1]
});
// Using Comparator.comparing (Java 8+)
PriorityQueue<Task> pq = new PriorityQueue<>(
Comparator.comparing(t -> t.priority)
);
Comparison Table
| Operation | PriorityQueue |
|---|---|
| Add/Offer | O(log n) |
| Poll/Remove | O(log n) |
| Peek | O(1) |
| Remove specific | O(n) ❌ |
| Contains | O(n) ❌ |
| Ordering | Min heap (default) |
Common LeetCode Patterns
Top K Elements:
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll(); // Remove smallest
}
}
// minHeap now contains top K largest elements
int kthLargest = minHeap.peek();
Merge K Sorted Lists:
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
// Add first node from each list
for (ListNode head : lists) {
if (head != null) pq.offer(head);
}
while (!pq.isEmpty()) {
ListNode node = pq.poll();
// Add to result...
if (node.next != null) pq.offer(node.next);
}
Sliding Window Maximum (alternative to deque):
PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0]);
// Store [value, index] pairs
6. String Utilities
String (Immutable)
Strings are immutable in Java - every modification creates a new string.
String s = "hello";
// Access
int len = s.length(); // O(1)
char c = s.charAt(0); // O(1)
// Substring
String sub = s.substring(1); // O(n), "ello"
String sub = s.substring(1, 4); // O(n), "ell" [inclusive, exclusive)
// Search
int idx = s.indexOf('l'); // O(n), first occurrence, returns -1 if not found
int idx = s.indexOf("ll"); // O(n), substring search
int lastIdx = s.lastIndexOf('l'); // O(n), last occurrence
boolean starts = s.startsWith("he"); // O(k) where k = prefix length
boolean ends = s.endsWith("lo"); // O(k) where k = suffix length
boolean contains = s.contains("ll"); // O(n)
// Comparison
boolean eq = s.equals("hello"); // O(n), content comparison
boolean eqIgnore = s.equalsIgnoreCase("HELLO"); // O(n)
int cmp = s.compareTo("world"); // O(n), lexicographic
// Modification (creates new string!)
String upper = s.toUpperCase(); // O(n)
String lower = s.toLowerCase(); // O(n)
String trim = s.trim(); // O(n), remove leading/trailing whitespace
String replaced = s.replace('l', 'r'); // O(n), "herro"
String replaced = s.replaceAll("l+", "L"); // O(n), regex
// Split
String[] parts = s.split(","); // O(n)
String[] parts = s.split(",", 2); // Limit to 2 parts
// Join (Java 8+)
String joined = String.join(",", "a", "b", "c"); // "a,b,c"
// Conversion
char[] chars = s.toCharArray(); // O(n)
byte[] bytes = s.getBytes(); // O(n)
// Check empty
boolean empty = s.isEmpty(); // O(1), checks length == 0
boolean blank = s.isBlank(); // O(n), checks if only whitespace (Java 11+)
StringBuilder (Mutable)
Use for frequent string modifications to avoid creating many intermediate strings.
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder(capacity); // Pre-allocate
StringBuilder sb = new StringBuilder("initial"); // With initial string
// Append
sb.append("hello"); // O(1) amortized
sb.append(123); // O(1), works with any type
sb.append(true); // O(1)
sb.append('x'); // O(1)
// Insert
sb.insert(0, "prefix"); // O(n), insert at index
// Delete
sb.deleteCharAt(0); // O(n), remove character at index
sb.delete(0, 3); // O(n), remove [start, end)
// Replace
sb.setCharAt(0, 'H'); // O(1), replace character
sb.replace(0, 3, "Hi"); // O(n), replace [start, end)
// Access
char c = sb.charAt(0); // O(1)
int len = sb.length(); // O(1)
// Reverse
sb.reverse(); // O(n)
// Convert to string
String s = sb.toString(); // O(n)
// Clear
sb.setLength(0); // O(1), resets length
StringBuffer (Thread-Safe)
Same API as StringBuilder but synchronized (slower). Use only if you need thread safety.
StringBuffer sbuf = new StringBuffer();
// Same methods as StringBuilder
Performance Comparison
| Operation | String | StringBuilder | StringBuffer |
|---|---|---|---|
| Concat/Modify | O(n) per op ❌ | O(1) amortized ✅ | O(1) amortized |
| Thread-safe | ✅ | ❌ | ✅ |
| Speed | Slow for many ops | ⚡ Fast | Slower (sync) |
| Use case | Few modifications | Many modifications | Thread-safe |
⚠️ Interview Tip: If you’re building a string in a loop, always use StringBuilder!
// ❌ BAD - O(n²) because each concat creates new string
String result = "";
for (String s : strings) {
result += s; // Creates new string every time!
}
// ✅ GOOD - O(n)
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
String result = sb.toString();
Common LeetCode Patterns
Palindrome Check:
// Method 1: Two pointers on original string
int left = 0, right = s.length() - 1;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) return false;
left++;
right--;
}
// Method 2: Reverse with StringBuilder
String reversed = new StringBuilder(s).reverse().toString();
return s.equals(reversed);
String Building:
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (isValid(c)) {
sb.append(c);
}
}
return sb.toString();
Character Frequency:
int[] freq = new int[26]; // For lowercase a-z
for (char c : s.toCharArray()) {
freq[c - 'a']++;
}
7. Array Utilities
Arrays Class
Static utility methods for array operations.
int[] arr = {5, 2, 8, 1, 9};
// Sorting
Arrays.sort(arr); // O(n log n), in-place, ascending
Arrays.sort(arr, 0, 3); // O(k log k), sort subarray [0, 3)
// For object arrays with comparator
Integer[] nums = {5, 2, 8, 1, 9};
Arrays.sort(nums, Collections.reverseOrder()); // Descending
Arrays.sort(nums, (a, b) -> a - b); // Custom comparator
// 2D array sorting
int[][] intervals = {{2, 5}, {1, 3}, {4, 6}};
Arrays.sort(intervals, (a, b) -> a[0] - b[0]); // Sort by first element
// Binary search (MUST be sorted first!)
Arrays.sort(arr);
int idx = Arrays.binarySearch(arr, 8); // O(log n)
// Returns index if found, or (-(insertion point) - 1) if not found
// Copy
int[] copy = Arrays.copyOf(arr, arr.length); // O(n), copy entire array
int[] copy = Arrays.copyOf(arr, 10); // O(n), resize (pad with 0)
int[] range = Arrays.copyOfRange(arr, 1, 4); // O(k), copy [1, 4)
// Fill
Arrays.fill(arr, 0); // O(n), fill entire array
Arrays.fill(arr, 0, 3, -1); // O(k), fill [0, 3) with -1
// Compare
boolean eq = Arrays.equals(arr1, arr2); // O(n), shallow equality
int cmp = Arrays.compare(arr1, arr2); // O(n), lexicographic
// Deep equals for multidimensional arrays
boolean eq = Arrays.deepEquals(matrix1, matrix2);
// Convert to string
String s = Arrays.toString(arr); // "[5, 2, 8, 1, 9]"
String s = Arrays.deepToString(matrix); // For multidimensional
// Convert to list
List<Integer> list = Arrays.asList(1, 2, 3); // Fixed-size list!
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); // Mutable
Primitive Array Operations
int[] arr = {1, 2, 3, 4, 5};
// Length (field, not method!)
int len = arr.length; // O(1), NO parentheses!
// Clone (shallow copy)
int[] copy = arr.clone(); // O(n)
// System.arraycopy (fastest way to copy)
int[] dest = new int[5];
System.arraycopy(arr, 0, dest, 0, 5); // O(n)
// Parameters: src, srcPos, dest, destPos, length
Collections Utility (for Lists)
List<Integer> list = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9));
// Sorting
Collections.sort(list); // O(n log n), ascending
Collections.sort(list, Collections.reverseOrder()); // Descending
Collections.sort(list, (a, b) -> a - b); // Custom comparator
// Binary search (MUST be sorted!)
Collections.sort(list);
int idx = Collections.binarySearch(list, 8); // O(log n)
// Min/Max
int min = Collections.min(list); // O(n)
int max = Collections.max(list); // O(n)
// Reverse
Collections.reverse(list); // O(n)
// Shuffle
Collections.shuffle(list); // O(n), random permutation
// Frequency
int count = Collections.frequency(list, 5); // O(n), count occurrences
// Fill
Collections.fill(list, 0); // O(n), replace all elements
// Swap
Collections.swap(list, 0, 4); // O(1), swap two elements
Common LeetCode Patterns
Two Pointers on Sorted Array:
Arrays.sort(arr);
int left = 0, right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return true;
else if (sum < target) left++;
else right--;
}
Binary Search Template:
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1; // Not found
Prefix Sum:
int[] prefix = new int[arr.length + 1];
for (int i = 0; i < arr.length; i++) {
prefix[i + 1] = prefix[i] + arr[i];
}
// Sum of [i, j] = prefix[j + 1] - prefix[i]
8. Quick Reference Tables
Time Complexity Summary
| Data Structure | Add/Insert | Remove | Access/Get | Search | Notes |
|---|---|---|---|---|---|
| ArrayList | O(1) end, O(n) middle | O(n) | O(1) | O(n) | Best for random access |
| LinkedList | O(1) ends | O(1) ends | O(n) ❌ | O(n) | Best for head/tail ops |
| HashSet | O(1) | O(1) | - | O(1) | Fast lookup, no order |
| TreeSet | O(log n) | O(log n) | - | O(log n) | Sorted, range queries |
| HashMap | O(1) | O(1) | O(1) | O(1) key | Fast key-value lookup |
| TreeMap | O(log n) | O(log n) | O(log n) | O(log n) key | Sorted keys, range queries |
| PriorityQueue | O(log n) | O(log n) | O(1) peek | O(n) | Min/Max heap |
| ArrayDeque | O(1) | O(1) | - | - | Best for stack/queue |
When to Use Which Data Structure
Need fast lookup by key?
├─ Order matters?
│ ├─ YES → TreeMap (sorted) or LinkedHashMap (insertion)
│ └─ NO → HashMap ✅
│
Need unique elements only?
├─ Order matters?
│ ├─ YES → TreeSet (sorted) or LinkedHashSet (insertion)
│ └─ NO → HashSet ✅
│
Need ordered sequence with duplicates?
├─ Random access by index?
│ ├─ YES → ArrayList ✅
│ └─ NO → LinkedList (if many head/tail operations)
│
Need FIFO (queue) or LIFO (stack)?
└─ ArrayDeque ✅
│
Need always access min/max?
└─ PriorityQueue ✅
Common Pitfalls
| Pitfall | Why It’s Wrong | Solution |
|---|---|---|
list.remove(1) on List<Integer> | Removes index 1, not value 1 | Use list.remove(Integer.valueOf(1)) |
Using == for strings | Compares references, not content | Use s1.equals(s2) |
poll() vs remove() | poll() returns null, remove() throws | Know the difference for nulls |
| String concat in loop | O(n²) time | Use StringBuilder |
LinkedList.get(i) in loop | O(n²) time | Use iterator or ArrayList |
| Modifying collection while iterating | ConcurrentModificationException | Use iterator.remove() |
| Forgetting to sort before binary search | Wrong results | Always sort first! |
arr.length() | Compile error (it’s a field) | Use arr.length (no parentheses) |
9. Common Interview Patterns by Data Structure
Pattern → Data Structure Mapping
| Pattern | Best Data Structure | Example Problems |
|---|---|---|
| Sliding Window | HashMap (frequency), Deque | Longest Substring Without Repeating Characters |
| Two Pointers | ArrayList (sorted) | Two Sum II, Container With Most Water |
| Monotonic Stack | ArrayDeque (as stack) | Next Greater Element, Largest Rectangle |
| Top K Elements | PriorityQueue | Kth Largest Element, Top K Frequent |
| Frequency Counting | HashMap | Valid Anagram, Group Anagrams |
| Fast Lookup | HashSet | Contains Duplicate, Two Sum |
| Range Queries | TreeMap/TreeSet | Count of Range Sum, My Calendar |
| LRU Cache | LinkedHashMap | LRU Cache (LC 146) |
| Merge K Sorted | PriorityQueue | Merge K Sorted Lists |
| Graph BFS/DFS | ArrayDeque (queue for BFS) | Number of Islands |
10. Conclusion: Your Interview Arsenal
Key Takeaways
- Default Choices: HashMap for lookups, ArrayList for sequences, ArrayDeque for stack/queue
- Need Sorted?: Use TreeMap/TreeSet for automatic ordering
- String Building?: Always use StringBuilder in loops
- Binary Search?: Remember to sort first with
Arrays.sort() - Time Complexity: Know the O(1) vs O(log n) vs O(n) operations
Practice Strategy
Week 1-2: Implement basic operations for each data structure
- Create small programs using ArrayList, HashMap, ArrayDeque
- Practice conversions (Array ↔ List, String ↔ char[])
Week 3-4: Solve pattern-specific problems
Week 5+: Time yourself and practice explaining your data structure choices
Final Interview Tips
✅ Do:
- Explain why you chose a particular data structure
- Mention time complexity of key operations
- Use modern APIs (ArrayDeque over Stack)
- Consider edge cases (null, empty, duplicates)
❌ Don’t:
- Use legacy classes (Vector, Hashtable, Stack)
- Forget to check for null/empty
- Mix up method names (poll vs pop, length vs length())
- Modify strings in loops without StringBuilder
Ready to Master Java for Interviews?
This reference guide covers 90% of the data structures you’ll use in LeetCode and real interviews. Bookmark this page and revisit it as you practice.
For deeper dives into specific algorithms, check out my other articles on Binary Search, Monotonic Stack, and LRU Cache.
Happy coding! 🚀
About the author: Jackey has 11+ years of experience at Microsoft, Booking.com, and Alibaba, conducting 500+ technical interviews. This guide distills practical knowledge from real interview scenarios.