Free lesson · DSA Mastery - Interview Prep, End to End
Java for DSA
Java for DSA
Java is the primary language used throughout this course. It is also one of the most common languages chosen for technical interviews, especially at companies like Amazon and Google. If you are coming to this course with strong Java skills, you can probably skim this topic. If you are coming from another language and want to use Java for interviews, this is the starting point.
This topic covers the Java APIs and idioms you actually need for DSA problems. It is not a general Java tutorial - it focuses specifically on the collections, the algorithms in the standard library, and the patterns that show up in interview code.
Why Java for Interviews
Interactive animation: Why Java works in interviews - and the price you pay in extra lines.
Java has a few practical advantages for interview prep:
- Strong type system. Type errors fail at compile time, which catches a lot of bugs you would only find at runtime in dynamic languages.
- Rich standard library.
java.utilincludes pre-built implementations of every data structure you commonly need. - Familiar to interviewers. Most senior engineers can read Java even if they do not write it daily.
- Aligned with company codebases. Amazon, Google, Netflix, and many others have substantial Java code, so interviewers are often familiar with idiomatic Java.
The trade-off: Java is more verbose than Python. A solution that fits in 10 lines of Python might be 25 lines of Java. For most interview problems, this is fine - the extra lines are usually type declarations and explicit collection setup, not algorithmic logic. But it means you have to type faster and plan your time accordingly.
The Core Data Structures You Need
Interactive animation: Java's toolbox: the collection to reach for, its key calls and what each one costs.
Java's java.util package gives you everything you need for interview problems. The most-used types:
| Need | Java Type | Notes |
|---|---|---|
| Array | int[], String[], T[] |
Fixed size, primitive or object |
| Dynamic array | ArrayList<T> |
Grows automatically |
| Hash map | HashMap<K, V> |
O(1) average |
| Sorted map | TreeMap<K, V> |
O(log n), keys in order |
| Hash set | HashSet<T> |
O(1) average |
| Sorted set | TreeSet<T> |
O(log n), elements in order |
| Stack | ArrayDeque<T> |
Faster than Stack |
| Queue / Deque | ArrayDeque<T> |
Used as queue or deque |
| Priority queue | PriorityQueue<T> |
Min-heap by default |
| Linked list | LinkedList<T> |
Rarely needed; prefer ArrayDeque |
A few of these need extra explanation, because their idiomatic Java usage differs from what new-to-Java engineers might expect.
Arrays in Java
Interactive animation: Primitive arrays against boxed arrays and ArrayList - and why printing an array needs Arrays.toString.
Java has two distinct array concepts: primitive arrays like int[] and collection types like ArrayList<Integer>. They are not interchangeable.
int[] primitive = new int[10];
Integer[] boxed = new Integer[10];
ArrayList<Integer> dynamic = new ArrayList<>();
Primitive arrays are faster and use less memory than ArrayList<Integer> because they avoid boxing. For interview problems with numeric data, primitive arrays are usually the right choice when the size is known.
ArrayList<T> is the right choice when:
- The size is not known up front.
- You need to grow or shrink the collection.
- You need methods like
add,remove,contains.
A few common gotchas:
int[]andInteger[]are not the same. You cannot putInteger[]into a method that expectsint[].Arrays.toString(arr)prints arrays.arr.toString()does not - it prints the array's memory address.Arrays.sort()sorts primitive arrays in place using dual-pivot quicksort. It sorts object arrays using TimSort.
Hash Maps and Hash Sets
HashMap is the workhorse data structure for interview problems. It gives you O(1) average put, get, and contains operations.
HashMap<String, Integer> counts = new HashMap<>();
counts.put("a", 1);
counts.put("a", counts.getOrDefault("a", 0) + 1);
counts.put("b", 5);
if (counts.containsKey("a")) {
int value = counts.get("a");
}
The getOrDefault method is essential for counting patterns. Without it, you have to check whether the key exists before incrementing - verbose and error-prone.
For sets:
HashSet<Integer> seen = new HashSet<>();
seen.add(5);
if (seen.contains(5)) {
// O(1)
}
seen.remove(5);
For sorted versions:
TreeMap<Integer, String> sorted = new TreeMap<>();
sorted.put(3, "three");
sorted.put(1, "one");
sorted.put(2, "two");
// keySet() returns in sorted order: [1, 2, 3]
TreeSet<Integer> sortedSet = new TreeSet<>();
sortedSet.add(3);
sortedSet.add(1);
// Iterates in sorted order
TreeMap and TreeSet are red-black trees underneath. Operations are O(log n) instead of O(1), but they keep things sorted, which matters for some problems.
Stack, Queue, and Deque
Interactive animation: One ArrayDeque, used as a stack and as a queue - the modern replacement for Stack.
This is a place where Java has a quirk worth knowing. The official Stack class exists but is considered legacy. The recommended replacement is ArrayDeque, which is faster and has a cleaner API.
For a stack:
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.push(3);
int top = stack.pop();
int peek = stack.peek();
boolean empty = stack.isEmpty();
For a queue (FIFO):
Deque<Integer> queue = new ArrayDeque<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
int front = queue.poll();
For a deque (double-ended queue, used in sliding window and monotonic queue problems):
Deque<Integer> deque = new ArrayDeque<>();
deque.offerFirst(1);
deque.offerLast(2);
deque.pollFirst();
deque.pollLast();
For most interview problems involving stacks or queues, ArrayDeque is the right choice. Avoid Stack, Vector, and LinkedList unless you have a specific reason.
PriorityQueue
Interactive animation: PriorityQueue is a min-heap by default; Comparator.reverseOrder() flips it.
PriorityQueue is Java's heap implementation. By default, it is a min-heap - the smallest element is at the top.
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(5);
minHeap.offer(2);
minHeap.offer(8);
int min = minHeap.poll();
For a max-heap, you pass a comparator:
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
maxHeap.offer(5);
maxHeap.offer(2);
maxHeap.offer(8);
int max = maxHeap.poll();
For custom objects, supply a comparator:
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
pq.offer(new int[]{3, 100});
pq.offer(new int[]{1, 200});
pq.offer(new int[]{2, 300});
PriorityQueue is used heavily in heap-based problems (Top K, Median from Data Stream, Merge K Sorted Lists). The comparator-based customization is essential for problems that prioritize by something other than natural ordering.
Common Idioms
A few patterns show up over and over in Java interview code.
Counting with HashMap
Interactive animation: The counting idiom line by line: getOrDefault, then entrySet to read the counts back.
HashMap<Character, Integer> counts = new HashMap<>();
for (char c : s.toCharArray()) {
counts.put(c, counts.getOrDefault(c, 0) + 1);
}
This pattern shows up in anagram problems, character-frequency problems, and many sliding-window problems. Memorize it.
Iterating a HashMap
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
}
for (String key : map.keySet()) { }
for (int value : map.values()) { }
Converting Between Collections
Interactive animation: The conversions you will need: list to int array with a stream, arrays to lists and sets.
List<Integer> list = new ArrayList<>();
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
List<Integer> list2 = Arrays.asList(1, 2, 3);
List<Integer> list3 = new ArrayList<>(Arrays.asList(1, 2, 3));
Set<Integer> set = new HashSet<>(list);
The primitive-array-to-List conversion is the most painful one. Memorize the idiom or look it up - interviewers will not penalize you for needing a second to recall the stream syntax.
Sorting
Interactive animation: Arrays.sort, Collections.sort and comparator lambdas - including sorting intervals by start.
int[] arr = {3, 1, 4, 1, 5};
Arrays.sort(arr);
Integer[] objArr = {3, 1, 4};
Arrays.sort(objArr, Collections.reverseOrder());
List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 4));
Collections.sort(list);
list.sort((a, b) -> b - a);
For custom sorting:
int[][] intervals = new int[][]{{1, 3}, {2, 6}, {8, 10}};
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
This pattern is essential for interval problems.
Tree Node and Linked List Node Classes
Interactive animation: The TreeNode and ListNode classes interview problems are built on.
Most tree problems use a standard node class:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
For linked list problems:
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
These are usually provided by the interview platform. You will see them constantly throughout the course.
Performance Notes
Interactive animation: String concatenation in a loop is O(n²); a StringBuilder makes it linear.
A few Java-specific performance points worth knowing for interviews:
String concatenation in a loop is O(n²). Use StringBuilder instead:
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
String result = sb.toString();
ArrayList.contains is O(n). If you need fast membership testing, use a HashSet.
Boxing has overhead. Integer is heavier than int. For numeric-heavy code, prefer primitive arrays where possible.
HashMap.put returns the old value. Sometimes useful for "was this already there?" checks without a separate containsKey call.
Interactive animation: Four performance notes in one place.
Boilerplate to Remember
Interactive animation: Habits to keep and habits to drop when writing interview Java.
For interviews, you usually need to remember this import:
import java.util.*;
That covers ArrayList, HashMap, HashSet, TreeMap, TreeSet, Deque, ArrayDeque, PriorityQueue, Comparator, and Collections.
A simple problem template:
public class Solution {
public int solve(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
return 0;
}
}
That is enough to get started on most interview problems. Type fast, plan your time, and lean on the standard library - Java's java.util does more work for you than most engineers initially realize.
The rest of this course will use Java throughout. The patterns covered here will appear in dozens of forms. By the end, the idioms above will feel automatic.