JAVA Cheat sheet for DSA and Collection frameworkd
metawritingJAVADSA
Array
// Initint[] arr = new int[20];int[] arr = new int[]{ 1,2,3,4,5 };int[][] grid = new int[10][10];// FillArrays.fill(arr, 10);// SortArrays.sort(arr); // ASCArrays.sort(arr, Collections.reverseOrder()); // DESC — requires Integer[], not int[]// ReverseCollections.reverse(Arrays.asList(arr));// Copyint[] copy = Arrays.copyOf(arr, arr.length);int[] slice = Arrays.copyOfRange(arr, 1, 4); // indices [1, 4)// Binary search (array must be sorted first)int idx = Arrays.binarySearch(arr, target); // returns index, or negative if not found
Collections.reverseOrder() only works on boxed types (Integer[]). For int[], sort then swap manually.
ArrayList
// InitList<Integer> list = new ArrayList<>();List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));// 2D listList<List<String>> grid = new ArrayList<>();for (int i = 0; i < n; i++) grid.add(new ArrayList<>());
Use LinkedList as a Deque when you need O(1) insert/remove at both ends. Random access get(i) is O(n) — use ArrayList if you need that.
Stack
// Prefer Deque over Stack (Stack extends Vector — synchronized, slow)Deque<Integer> stack = new ArrayDeque<>();
Method
Description
Cost
stack.push(val)
Push onto top
O(1)
stack.pop()
Remove and return top — throws if empty
O(1)
stack.peek()
View top without removing
O(1)
stack.isEmpty()
Boolean check
O(1)
stack.size()
Element count
O(1)
java.util.Stack is legacy. Always use Deque<T> stack = new ArrayDeque<>().
Queue
Queue<Integer> q = new ArrayDeque<>(); // faster than LinkedList in practice
Method
Description
Cost
q.offer(val)
Enqueue — returns false if full
O(1)
q.add(val)
Enqueue — throws IllegalStateException if full
O(1)
q.poll()
Dequeue head — returns null if empty
O(1)
q.remove()
Dequeue head — throws if empty
O(1)
q.peek()
View head — returns null if empty
O(1)
q.isEmpty() / q.size()
Check / count
O(1)
offer vs add
Method
Queue full?
On success
add()
throws IllegalStateException
returns true
offer()
returns false
returns true
Default to offer / poll / peek — they never throw on capacity issues.
Deque (Double-Ended Queue)
Deque<Integer> dq = new ArrayDeque<>();
ArrayDeque is the single best general-purpose structure — use it as both Stack and Queue.
Method
Description
Cost
dq.offerFirst(val) / dq.offerLast(val)
Add to front / back
O(1)
dq.pollFirst() / dq.pollLast()
Remove from front / back — null if empty
O(1)
dq.peekFirst() / dq.peekLast()
View front / back — null if empty
O(1)
Deque is the backbone of sliding window maximum/minimum problems. Use it as a monotonic deque to get O(n) total over a naive O(nk).
PriorityQueue (Heap)
// Min-heap (default — smallest at top)PriorityQueue<Integer> minH = new PriorityQueue<>();// Max-heapPriorityQueue<Integer> maxH = new PriorityQueue<>(Collections.reverseOrder());// Custom comparator — sort int[] by index 1PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); // min-heap on [1]PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[1] - a[1]); // max-heap on [1]
Method
Description
Cost
pq.offer(val)
Insert
O(log n)
pq.peek()
View root (min/max)
O(1)
pq.poll()
Remove and return root
O(log n)
pq.size() / pq.isEmpty()
Count / empty check
O(1)
Iterating over a PriorityQueue does not guarantee sorted order. Only poll() extracts in order.
Common PQ Patterns
// Top K largest elements — maintain a min-heap of size KPriorityQueue<Integer> pq = new PriorityQueue<>();for (int num : nums) { pq.offer(num); if (pq.size() > k) pq.poll(); // evict smallest}// pq.peek() == kth largest// Top K frequent elementsMap<Integer, Integer> freq = new HashMap<>();for (int n : nums) freq.merge(n, 1, Integer::sum);PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);for (Map.Entry<Integer, Integer> e : freq.entrySet()) { pq.offer(new int[]{e.getKey(), e.getValue()}); if (pq.size() > k) pq.poll();}
HashMap
Map<String, Integer> map = new HashMap<>();Map<Integer, List<String>> map = new HashMap<>();
Method
Description
Cost
map.put(k, v)
Insert or overwrite
O(1) avg
map.get(k)
Get value or null
O(1) avg
map.getOrDefault(k, def)
Get value or return default
O(1) avg
map.containsKey(k)
Key existence check
O(1) avg
map.remove(k)
Delete entry
O(1) avg
map.size() / map.isEmpty()
Count / empty check
O(1)
map.keySet()
Set of all keys
—
map.values()
Collection of all values
—
map.entrySet()
Set of key-value pairs
—
map.putIfAbsent(k, v)
Put only if key absent
O(1) avg
map.merge(k, 1, Integer::sum)
Insert or combine with existing
O(1) avg
// Iteratefor (Map.Entry<String, Integer> e : map.entrySet()) { String k = e.getKey(); int v = e.getValue();}// computeIfAbsent — creates value if key absent (use for nested structures)map.computeIfAbsent(key, k -> new ArrayList<>()).add(item);// Frequency count — two equivalent waysmap.merge(num, 1, Integer::sum);map.put(num, map.getOrDefault(num, 0) + 1);
TreeMap
Map<String, Integer> tm = new TreeMap<>(); // ASCMap<String, Integer> tm = new TreeMap<>(Collections.reverseOrder()); // DESC
Method
Description
Cost
tm.put / tm.get / tm.remove
Standard map ops
O(log n)
tm.firstEntry() / tm.lastEntry()
Min / max entry
O(log n)
tm.firstKey() / tm.lastKey()
Min / max key
O(log n)
tm.floorKey(k)
Largest key ≤ k
O(log n)
tm.ceilingKey(k)
Smallest key ≥ k
O(log n)
tm.lowerKey(k)
Largest key < k
O(log n)
tm.higherKey(k)
Smallest key > k
O(log n)
tm.subMap(k1, k2)
View of keys in [k1, k2)
O(log n)
tm.keySet() / tm.values() / tm.entrySet()
Ordered iteration
O(n)
floorKey / ceilingKey are critical for interval and range problems. Know them cold.
TreeSet<Integer> ts = new TreeSet<>(); // ASCTreeSet<Integer> ts = new TreeSet<>(Comparator.reverseOrder()); // DESC
Method
Description
Cost
ts.add / ts.contains / ts.remove
Standard set ops
O(log n)
ts.first() / ts.last()
View min / max — no removal
O(log n)
ts.pollFirst() / ts.pollLast()
Remove and return min / max
O(log n)
ts.floor(val)
Largest element ≤ val
O(log n)
ts.ceiling(val)
Smallest element ≥ val
O(log n)
ts.lower(val)
Largest element < val
O(log n)
ts.higher(val)
Smallest element > val
O(log n)
ts.subSet(a, b)
View of [a, b)
O(log n)
StringBuilder + String Utils
StringBuilder sb = new StringBuilder();StringBuilder sb = new StringBuilder("hello");
Method
Description
sb.append(c / str / num)
Append char, string, or number
sb.insert(i, str)
Insert at index
sb.delete(i, j)
Delete [i, j)
sb.deleteCharAt(i)
Remove char at index
sb.replace(i, j, str)
Replace [i, j) with str
sb.reverse()
Reverse in-place
sb.toString()
Convert to String
sb.charAt(i)
Get char at index
sb.setCharAt(i, c)
Set char at index
sb.length()
Number of chars
sb.indexOf(str)
First occurrence index or -1
// ConversionsString s = String.valueOf(42); // int → Stringint n = Integer.parseInt("42"); // String → int// Char frequency (a-z only)int[] freq = new int[26];for (char c : s.toCharArray()) freq[c - 'a']++;// Useful String methodss.substring(i, j) // [i, j)s.toLowerCase() / s.toUpperCase()s.trim() // strip leading/trailing whitespaces.replace('a', 'b')s.contains("abc")s.startsWith("ab") / s.endsWith("cd")s.equals(other) // content equality — never use ==s.compareTo(other) // lexicographic comparisonString.join("-", "a", "b", "c") // "a-b-c"String.valueOf(charArray) // char[] → String
String concatenation with + in a loop is O(n²). Always use StringBuilder.
Bit Manipulation
// Core operationsa & b // ANDa | b // ORa ^ b // XOR~a // bitwise NOTa << n // left shift (× 2^n)a >> n // signed right shift (÷ 2^n)a >>> n // unsigned right shift
// Essential tricksx & 1 // 1 = odd, 0 = evenx & (x - 1) // clear lowest set bitx == 0 // true only if x is 0 after above → x was power of 2(x >> n) & 1 // get nth bit (0-indexed from right)x | (1 << n) // set nth bitx & ~(1 << n) // clear nth bitx ^ (1 << n) // toggle nth bitInteger.bitCount(x) // number of set bits (popcount)Integer.highestOneBit(x) // value of highest set bit// XOR identity: a ^ a = 0, a ^ 0 = a// → find single non-duplicate where all others appear twiceint result = 0;for (int n : nums) result ^= n;// Power of 2 checkboolean isPow2 = n > 0 && (n & (n - 1)) == 0;// Enumerate all subsets of n elements (bitmask)for (int mask = 0; mask < (1 << n); mask++) { for (int i = 0; i < n; i++) { if ((mask & (1 << i)) != 0) { /* element i is in subset */ } }}
Two Pointers
// Opposite ends — sorted array, pair sumint l = 0, r = arr.length - 1;while (l < r) { int sum = arr[l] + arr[r]; if (sum == target) { /* found */ break; } else if (sum < target) l++; else r--;}// Fast / slow — cycle detection (Floyd's)int slow = head, fast = head;while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { /* cycle detected */ break; }}
Sliding Window
// Fixed size window of length kint windowSum = 0;for (int i = 0; i < k; i++) windowSum += arr[i];int maxSum = windowSum;for (int i = k; i < arr.length; i++) { windowSum += arr[i] - arr[i - k]; maxSum = Math.max(maxSum, windowSum);}// Variable size window — shrink left when window becomes invalidint l = 0, result = 0;Map<Character, Integer> freq = new HashMap<>();for (int r = 0; r < s.length(); r++) { freq.merge(s.charAt(r), 1, Integer::sum); while (freq.size() > k) { // condition violated freq.merge(s.charAt(l), -1, Integer::sum); if (freq.get(s.charAt(l)) == 0) freq.remove(s.charAt(l)); l++; } result = Math.max(result, r - l + 1);}
Prefix Sum
// 1Dint[] prefix = new int[n + 1];for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + arr[i];// sum of arr[l..r] inclusiveint rangeSum = prefix[r + 1] - prefix[l];// 2Dint[][] p = new int[m + 1][n + 1];for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) p[i][j] = grid[i-1][j-1] + p[i-1][j] + p[i][j-1] - p[i-1][j-1];// sum of submatrix (r1,c1) to (r2,c2) inclusiveint sum = p[r2+1][c2+1] - p[r1][c2+1] - p[r2+1][c1] + p[r1][c1];
Binary Search
// Standard — find exact target in sorted arrayint l = 0, r = arr.length - 1;while (l <= r) { int mid = l + (r - l) / 2; // never (l + r) / 2 — overflows if (arr[mid] == target) return mid; else if (arr[mid] < target) l = mid + 1; else r = mid - 1;}return -1;// Lower bound — leftmost index where arr[i] >= targetint l = 0, r = arr.length;while (l < r) { int mid = l + (r - l) / 2; if (arr[mid] >= target) r = mid; else l = mid + 1;}// l is the answer// Upper bound — leftmost index where arr[i] > target (i.e. r-1 is last occurrence of target)int l = 0, r = arr.length;while (l < r) { int mid = l + (r - l) / 2; if (arr[mid] > target) r = mid; else l = mid + 1;}// l - 1 is last occurrence of target// Binary search on answer — "search on the result space, not the array"// Pattern: find minimum X such that condition(X) is trueint l = minPossible, r = maxPossible;while (l < r) { int mid = l + (r - l) / 2; if (condition(mid)) r = mid; else l = mid + 1;}// l is the minimum valid answer
Always mid = l + (r - l) / 2. (l + r) / 2 overflows when both are large.
Graph Traversal
// Build adjacency listMap<Integer, List<Integer>> graph = new HashMap<>();for (int[] edge : edges) { graph.computeIfAbsent(edge[0], k -> new ArrayList<>()).add(edge[1]); graph.computeIfAbsent(edge[1], k -> new ArrayList<>()).add(edge[0]); // undirected}// BFS — shortest path in unweighted graph, level-by-levelQueue<Integer> queue = new ArrayDeque<>();boolean[] visited = new boolean[n];queue.offer(start);visited[start] = true;int level = 0;while (!queue.isEmpty()) { int size = queue.size(); // freeze current level count for (int i = 0; i < size; i++) { int node = queue.poll(); for (int nb : graph.getOrDefault(node, new ArrayList<>())) { if (!visited[nb]) { visited[nb] = true; queue.offer(nb); } } } level++;}// DFS — iterativeDeque<Integer> stack = new ArrayDeque<>();boolean[] visited = new boolean[n];stack.push(start);while (!stack.isEmpty()) { int node = stack.pop(); if (visited[node]) continue; visited[node] = true; for (int nb : graph.getOrDefault(node, new ArrayList<>())) if (!visited[nb]) stack.push(nb);}// DFS — recursiveboolean[] visited = new boolean[n];void dfs(int node) { visited[node] = true; for (int nb : graph.getOrDefault(node, new ArrayList<>())) if (!visited[nb]) dfs(nb);}
Grid BFS / DFS
int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}}; // 4-directional// 8-directional: also add {1,1},{1,-1},{-1,1},{-1,-1}boolean[][] visited = new boolean[m][n];Queue<int[]> q = new ArrayDeque<>();q.offer(new int[]{startR, startC});visited[startR][startC] = true;while (!q.isEmpty()) { int[] curr = q.poll(); for (int[] d : dirs) { int nr = curr[0] + d[0]; int nc = curr[1] + d[1]; if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited[nr][nc]) { visited[nr][nc] = true; q.offer(new int[]{nr, nc}); } }}
Sorting Comparators
// Sort 2D array by first col, break ties by second colArrays.sort(intervals, (a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);// Sort strings by length, then lexicographicallylist.sort((a, b) -> a.length() != b.length() ? a.length() - b.length() : a.compareTo(b));// Sort by absolute valueArrays.sort(arr, (a, b) -> Math.abs(a) - Math.abs(b));
(a - b) comparators can silently overflow for large negatives/positives. Use Integer.compare(a, b) when values may be extreme.
Math & Number Utils
Integer.MAX_VALUE // 2^31 - 1 ≈ 2.1 billionInteger.MIN_VALUE // -2^31 ≈ -2.1 billionLong.MAX_VALUE // use when intermediate products exceed int rangeMath.max(a, b) / Math.min(a, b)Math.abs(x)Math.pow(base, exp) // returns doubleMath.sqrt(x) // returns double(int)(Math.log(x) / Math.log(2)) // log base 2// GCD / LCMint gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }int lcm(int a, int b) { return a / gcd(a, b) * b; }// Overflow guard for multiplicationlong result = (long) a * b;
Useful Java Tricks
// Convert List<Integer> → int[]int[] arr = list.stream().mapToInt(Integer::intValue).toArray();// Convert int[] → List<Integer>List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());// Max / min / sum of array via streamint max = Arrays.stream(arr).max().getAsInt();int min = Arrays.stream(arr).min().getAsInt();int sum = Arrays.stream(arr).sum();// Fill 2D dp arrayfor (int[] row : dp) Arrays.fill(row, Integer.MAX_VALUE);// Char ↔ digitint d = c - '0';char c = (char)('0' + d);// Character checksCharacter.isDigit(c)Character.isLetter(c)Character.isAlphabetic(c)Character.isUpperCase(c) / Character.isLowerCase(c)Character.toLowerCase(c) / Character.toUpperCase(c)// Ternary for inline min/maxint clamp = Math.max(lo, Math.min(val, hi));// Integer overflow safe addition checkboolean overflows = (long) a + b > Integer.MAX_VALUE;