Skip to content
Skilled.dev

Language preparation

Java coding interview preparation: collections, numbers, and traversal

Prepare with HashMap, ArrayDeque, safe comparators, UTF-16 text, and tested Java implementations of Two Sum and graph traversal.

Published · 5 min read

Java interview practice usually depends on choosing a small set of collections and using their contracts accurately. A short algorithm can fail because an absent map result is unboxed, a comparator overflows, or a queue operation removes from the wrong end. Prepare those operations alongside the algorithm's invariant.

The examples use Java 17-compatible syntax and standard-library collections. They are ordinary functions inside a small class, not the exact signature of every exercise. Match the lesson's provided types and return convention before pasting an implementation into its editor.

Choose collections by the next operation

Use an array when the size is fixed and indexed primitive values are enough. An ArrayList provides a resizable indexed collection of references; ArrayList<Integer> therefore involves boxed integer values. A HashMap associates a key with a value, while a HashSet records membership. An ArrayDeque supports stack or queue operations at its ends.

For a FIFO queue, pair addLast with removeFirst. For a stack, pair addLast with removeLast. Choosing one pair consistently makes the processing order visible. An ArrayDeque cannot contain null, so enqueue only existing tree children instead of treating null as an ordinary node marker. Its end operations have amortized constant cost under the library contract. See the ArrayDeque reference.

A priority queue answers a different question: which queued value has the smallest priority according to its comparator? Removing from a priority queue does not preserve arrival order. Choose it for priority-based work, and use a deque for the layers of an unweighted BFS.

Preserve absence, index zero, and numeric range

Two Sum can use a map from earlier value to index. Look up the complement before storing the current element so one position cannot match itself. An index of zero is a valid successful result. In this implementation, a null lookup means absent because the map only stores actual integer indexes, never null values.

The arithmetic uses long keys even though the input values and target are int. The cast happens before subtraction. An int subtraction that already overflowed cannot be repaired by assigning its result to a long afterward.

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

final class JavaInterview {
    static Optional<int[]> twoSum(int[] values, int target) {
        Map<Long, Integer> previous = new HashMap<>();
        for (int index = 0; index < values.length; index++) {
            long complement = (long) target - values[index];
            Integer earlier = previous.get(complement);
            if (earlier != null) return Optional.of(new int[] {earlier, index});
            previous.put((long) values[index], index);
        }
        return Optional.empty();
    }

    static List<Integer> bfsOrder(Map<Integer, List<Integer>> graph, int start) {
        ArrayDeque<Integer> queue = new ArrayDeque<>();
        Set<Integer> seen = new HashSet<>();
        List<Integer> order = new ArrayList<>();
        seen.add(start);
        queue.addLast(start);
        while (!queue.isEmpty()) {
            int node = queue.removeFirst();
            order.add(node);
            for (int neighbor : graph.getOrDefault(node, List.of())) {
                if (seen.add(neighbor)) queue.addLast(neighbor);
            }
        }
        return order;
    }
}

Both functions assume non-null inputs and, for the graph, non-null neighbor lists and labels. A missing adjacency key means no outgoing edges. The returned BFS order follows each neighbor list's order and includes the start even if it has no listed neighbors. No iteration over the map's keys determines the traversal.

Two Sum takes expected O(n) time and O(n) map storage under the usual well-dispersed hash model. BFS takes expected O(V + E) work over the reachable vertices and examined edges, with O(V) visited and queue storage. HashMap's documentation qualifies its basic-operation cost by hash dispersion and does not promise map iteration order.

Keep equality separate from object identity

Use value equality for boxed values and strings when the problem asks whether their contents match. Comparing two Integer objects with == compares references when neither side is being unboxed. Small examples may appear to work because some boxed values are cached. A test using larger values can expose the mistaken identity assumption.

The null check above deliberately asks whether a lookup returned an object. After that check, placing the Integer into the primitive result array unboxes it safely. If a map's valid values include null, get alone cannot distinguish absence from a present null; use the map's presence operation when that distinction belongs to the contract.

For composite keys, choose an immutable representation with consistent equality and hashing. Mutating fields used in a key's hash after insertion can make lookups fail even though the object remains in the map. Arrays also do not automatically become content-based keys merely because they contain the same numbers.

Write comparators without subtraction overflow

Use Integer.compare(a, b) or Long.compare(a, b) for numeric comparison. A comparator returning a - b can overflow and reverse the intended ordering. Reversing the subtraction does not solve that problem for a descending comparator.

Java's PriorityQueue exposes a minimum under its chosen order. To keep the K largest stream values, a size-K minimum heap exposes the weakest retained value for replacement. Iterating over the queue is not a sorted-output operation; repeatedly removing its head or sorting a separate result has a different cost. The PriorityQueue reference specifies its ordering and operation bounds.

For sorted arrays or intervals, state whether sorting may mutate the caller's input. Copying an array first changes the space budget. A shallow copy of a collection still refers to the same mutable element objects, which matters when interval fields are edited after sorting.

Define the text unit before counting characters

Java strings use UTF-16. length and charAt describe code units; some Unicode code points use two code units. A fixed-size alphabet table is appropriate when an exercise promises lowercase English letters. It is not automatically correct for arbitrary text containing supplementary characters.

For code-point processing, use a code-point-aware traversal or convert with codePoints().toArray() when the allocation is acceptable. That conversion makes indexing convenient but adds storage. Code points still differ from user-perceived grapheme clusters, so clarify which unit a palindrome, frequency count, or substring length should use.

Recursion is another runtime consideration. A correct recursive DFS can exhaust the call stack on a long chain. Practice the explicit deque or stack form and include its retained frontier in the memory analysis rather than treating recursion as free.

Practice a sequence with observable failure cases

Start with Two Sum, bracket matching, and BFS. Test repeated values, no pair, index zero, a cyclic graph, an isolated start, and extreme int values whose complement does not fit in int. Compare returned pair validity with a direct two-loop reference.

Then implement a boundary search and a top-K heap. Explain the difference between absent and zero, value and identity, queue order and priority order, and arithmetic width before running the tests. Use the complexity reference to state collection assumptions and the study-plan builder to reserve time for another attempt without the previous code open.

Worked lesson walkthroughs

58 reading lessons with code examples in this language.

Concepts

Concept lesson

Arrays in Java

Learn array insertion in Java. Trace a copied result, explain shifting costs, and check empty inputs and endpoint positions without changing the original.

Concept lesson

Big O time and space complexity in Java

Analyze time and space complexity in Java with a suffix-copy example. Count nested work, returned storage, and allocation instead of counting loops alone.

Concept lesson

Hash Tables in Java

Count frequencies with a hash map in Java. Preserve input order, distinguish missing keys from zero, and explain expected lookup time and retained storage.

Concept lesson

Strings in Java

Practice string construction in Java with a repeat-text example. Explain builders, copies, Unicode representation, output size, and boundary cases.

Concept lesson

Palindromes, permutations, and anagrams in Java

Check an ASCII-normalized palindrome in Java. Trace two-pointer comparisons, case handling, ignored characters, and the limits of the text contract.

Concept lesson

Recursion in Java

Trace recursive factorial in Java from the base case through returning calls. Explain termination, stack space, integer limits, and boundary tests.

Concept lesson

Logarithmic time in Java: repeated halving and search

Understand logarithmic loops in Java by counting integer halvings. Test powers of two, explain rounding, and derive the exact step count.

Concept lesson

Binary search in Java: invariants and boundary tests

Write first-occurrence binary search in Java. Trace half-open bounds, duplicate values, missing targets, and the random-access assumption behind O(log n).

Concept lesson

Sorting in Java

Return a numerically sorted copy in Java. Preserve duplicates and the original input, choose the right library operation, and account for copied storage.

Concept lesson

Linked Lists in Java

Find a linked list's middle in Java with slow and fast runners. Define the even-length result, handle an empty list, and separate construction from traversal.

Concept lesson

Pointers in Java

Trace shared mutation and reference rebinding in Java. Follow two aliases through one object update and a new allocation, with explicit ownership notes.

Concept lesson

Queues in Java

Practice FIFO queue behavior in Java. Compare efficient front removal with a head cursor, preserve repeated values, and count fill-and-drain costs.

Concept lesson

Stacks in Java

Practice LIFO stack behavior in Java. Trace push and pop, separate empty state from zero payloads, and explain node ownership and end-operation costs.

Concept lesson

Trees in Java

Compute binary-tree edge height in Java. Read heap-indexed nullable slots, handle an empty root, and account for reachable nodes and recursion depth.

Concept lesson

Tree traversal in Java: in-order, pre-order, and post-order

Trace in-order binary-tree traversal in Java. Explain nullable child positions, visit order, recursion space, and when the output is actually sorted.

Concept lesson

Binary Search Trees in Java

Search a binary search tree in Java. Follow one ordered path, handle absent children, and relate search cost to height without assuming balance.

Concept lesson

Graphs in Java

Read graph adjacency lists in Java and compute out-degrees. Define vertex IDs, parallel edges, self-loops, representation costs, and input assumptions.

Concept lesson

Depth-First Search in Java

Implement iterative DFS in Java. Preserve listed neighbor order, skip repeated visits, trace a shared descendant, and explain pending-stack costs.

Concept lesson

Breadth-First Search in Java

Implement BFS in Java with FIFO order and enqueue-time discovery. Trace graph layers, cycles, shared descendants, and visited-storage costs.

Concept lesson

Subproblems and Overlapping Subproblems in Java

Count naive Fibonacci calls in Java. Trace overlapping states, include base-case work, and identify the cache key before applying memoization.

Concept lesson

Memoization in Java

Memoize Fibonacci in Java and count distinct computed states. Preserve cached zero, define cache lifetime, and explain remaining recursion depth.

Concept lesson

Bottom-Up vs. Top-Down in Java

Build a bottom-up Fibonacci table in Java. Follow dependency order, test zero input, and compare full-table storage with rolling-state alternatives.

Concept lesson

Dynamic Programming in Java

Solve minimum coin count in Java. Trace the recurrence, represent unreachable states, test a greedy counterexample, and explain amount-based table costs.

Data structure implementations

Implementation tutorial

Implement a dynamic array in Java

Implement a map-backed teaching array in Java. Trace push, pop, insertion, and removal, including logical length, missing indices, and obsolete entries.

Implementation tutorial

Implement a hash table in Java: collisions, updates, and removal

Build a hash table in Java with separate chaining. Follow colliding keys through lookup, update, and deletion, and explain the limits of a fixed teaching hash.

Implementation tutorial

Implement a linked list in Java: head, tail, and node identity

Build a doubly linked list in Java. Trace prepend and append, verify reciprocal links and both endpoints, and explain ownership and retention.

Implementation tutorial

Implement a queue in Java: FIFO links and empty transitions

Implement a linked queue in Java. Trace FIFO order, the last removal, and refilling an empty queue while preserving first and last endpoint invariants.

Implementation tutorial

Implement a stack in Java: push, pop, and ownership

Implement a linked stack in Java. Follow the top link through push, peek, and pop, including empty state, returned nodes, and retained chains.

Implementation tutorial

Implement a binary search tree in Java: insert and search

Build a binary search tree in Java. Trace insertion and search, preserve duplicate keys on the right, and test skewed shapes without assuming balancing.

Implementation tutorial

Implement a graph in Java: adjacency lists and edge removal

Build an adjacency-list graph in Java. Trace directed and undirected edges, self-loops, parallel entries, and removal of incoming and outgoing edges.

Practice problems

Practice walkthrough

Two Sum in Java: all index pairs with HashMap

Build a Java HashMap solution for every matching index pair. Handle Integer null checks, avoid complement overflow, and convert the result to int[][] with tests.

Practice walkthrough

Valid brackets in Java: ArrayDeque and ordered matching

Use ArrayDeque as a stack to validate brackets in Java. Handle pop safely, choose character types, ignore ordinary text, and verify a complete set of edge cases.

Practice walkthrough

Product of array except self in Java with long arrays

Implement prefix and suffix products with long[] in Java. Initialize the output correctly, handle zeros without division, and state the overflow assumptions with tests.

Practice walkthrough

Counting sort for ages in Java: worked solution

Sort bounded ages with a frequency table, preserving duplicate values. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Best stock profit in Java: one transaction

Find the best single chronological stock trade with one scan. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Most frequent email in Java: hash-map solution

Count email occurrences and return the unique most frequent address. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

First Bad Version in Java: boundary binary search

Find the first true value in a monotone version predicate. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Reverse a linked list in Java: pointer walkthrough

Reverse a linked list by moving nodes from an untouched suffix to a reversed prefix. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Remove kth node from end in Java: zero-based deletion

Delete the zero-based kth node from the end of a linked list. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Merge sorted linked lists in Java: Combine Blockchains

Merge two sorted linked chains while preserving duplicate timestamps. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Count Islands in Java: DFS flood-fill walkthrough

Count side-connected land components with a destructive flood fill of the working grid. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Validate a binary search tree in Java: inherited bounds

Validate every binary-tree node against bounds inherited from all its ancestors. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Binary tree maximum depth in Java: count edges

Measure a binary tree’s longest root-to-leaf path in edges. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Lowest common ancestor in Java: return the original node

Find the lowest common ancestor in a general binary tree and return the original node. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Generate string permutations in Java: positional results

Generate positional string permutations, retaining repeated results for repeated characters. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Group palindrome permutations in Java: counts and keys

Filter palindrome permutations, then group retained strings by character multiset. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Merge intervals in Java: Interview Scheduler

Merge sorted interval coverage with an explicit touching-endpoint rule. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Min-max stack in Java: constant-time extrema

Support stack extrema through histories that retain duplicate record values. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

BFS shortest path in Java: Pilot a Rocket

Find an unweighted shortest route and reconstruct it from predecessor links. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Maze reachability in Java: memoized down/right search

Memoize directed maze reachability while keeping unknown distinct from false. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Search a rotated sorted array in Java: Shifted Search

Search a distinct rotated sorted array by identifying an ordered half. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Search a sorted matrix in Java: staircase walkthrough

Eliminate a row or column at each step in a row-and-column sorted matrix. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

House Robber in Java: maximum nonadjacent sum

Maximize a nonadjacent selection with two rolling prefix optima. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Sum decimal digits in Java: recursive solution

Sum decimal digits through a decreasing recursive integer decomposition. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Count 1, 2, or 3-step paths in Java: Three Moves

Count ordered one-, two-, and three-step routes with rolling dynamic programming. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Coin change in Java: minimum-coin dynamic programming

Minimize unlimited coin usage with a bottom-up amount table. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Validate Sudoku in Java: rows, columns, and subsquares

Validate filled Sudoku entries against rows, columns, and subsquares. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.

Practice walkthrough

Spiral matrix traversal in Java: Walk a Matrix

Traverse a rectangle in clockwise spiral order using shrinking boundaries. Follow the Java implementation, its correctness argument, worked example, complexity, and boundary tests.