Guide contents

Lesson 3 of 164

Arrays in Java Interviews

Most interview problems give you a list of numbers. In Java that list can have a few different types, and picking the right one for the method signature matters.

Type What it is Use it for
int[] fixed-length array of primitives, length set at creation most interview inputs and outputs, new int[26] letter counts
int[][] array of arrays (a matrix) grids and tables
ArrayList<Integer> growable list of boxed Integer objects building results when the size is unknown
List<Integer> the interface that ArrayList implements parameter and return types that accept any list

An array has a fixed length field and is passed by reference: a method that receives an int[] sees and can change the caller's elements. A method cannot change the length of an array, so a method that adds or removes elements returns a new array, returns a new length (as in remove-duplicates problems), or uses a list.

Java
import java.util.Arrays;

public class Main {
    static long total(int[] nums) {
        long sum = 0;
        for (int x : nums) {
            sum += x;
        }
        return sum;
    }

    static long total(int[] nums, int from, int to) { // half-open range [from, to)
        long sum = 0;
        for (int i = from; i < to; i++) {
            sum += nums[i];
        }
        return sum;
    }

    public static void main(String[] args) {
        int[] array = {1, 2, 3};
        int[] other = {10, 20, 30, 40};
        System.out.println(total(array) + " " + total(other) + " " + total(other, 1, 3));
        System.out.println(Arrays.toString(Arrays.copyOfRange(other, 1, 3)));
    }
}
Output
6 100 50
[20, 30]

Java has no slice type. A sub-range is either passed as two indices (from, to) or copied with Arrays.copyOfRange, which costs O(k) for k elements. Passing indices avoids the copy.

When to choose a type: use int[] when the size is known and the values are primitives. Use ArrayList<Integer> when the size changes or when a collection API (sets, maps, sorting with a comparator) needs objects.

Methods worth knowing

java.util.Arrays holds the helpers for arrays. An array prints as an address-like string with println, so print it with Arrays.toString.

Java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] v = {4, 1, 3, 1, 5};

        // Reading
        System.out.println(v[0] + " " + v[v.length - 1]);
        System.out.println(Arrays.stream(v).max().getAsInt());

        // Rearranging in place
        int tmp = v[0];
        v[0] = v[4];
        v[4] = tmp;
        System.out.println(Arrays.toString(v));

        Arrays.sort(v);
        System.out.println(Arrays.toString(v) + " " + Arrays.binarySearch(v, 4));

        // Changing the length: copy into a new array
        int[] bigger = Arrays.copyOf(v, 7);
        System.out.println(Arrays.toString(bigger));
        int[] smaller = Arrays.copyOf(v, 3);
        System.out.println(Arrays.toString(smaller));

        // Filling and comparing
        int[] zeros = new int[3];
        Arrays.fill(zeros, 7);
        System.out.println(Arrays.toString(zeros) + " " + Arrays.equals(zeros, new int[]{7, 7, 7}));
    }
}
Output
4 5
5
[5, 1, 3, 1, 4]
[1, 1, 3, 4, 5] 3
[1, 1, 3, 4, 5, 0, 0]
[1, 1, 3]
[7, 7, 7] true

Arrays.sort on an int[] sorts in place in ascending order. Arrays.binarySearch needs a sorted array and returns the index of a match. When the value is absent it returns a negative number: -(insertion point) - 1. Arrays.copyOf pads with zeros when the new length is larger. Arrays.equals compares contents, while == and .equals on an array compare identity.

An array index outside 0..length-1 throws ArrayIndexOutOfBoundsException. ArrayList works the same way with get(i) and IndexOutOfBoundsException.

ArrayList operations that appear in interviews:

Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(4, 1, 3, 1, 5));
        list.add(9);                          // append, O(1) amortized
        list.remove(Integer.valueOf(1));      // removes the first value 1, O(n)
        list.remove(0);                       // removes the element at index 0, O(n)
        Collections.sort(list);
        Collections.reverse(list);
        System.out.println(list + " " + list.size() + " " + list.contains(5));
    }
}
Output
[9, 5, 3, 1] 4 true

list.remove(0) takes an int and removes by index. list.remove(Integer.valueOf(1)) takes an object and removes by value. Mixing them up is a common bug.

The five patterns

Most array problems are one of these five patterns, or a combination.

1. One pass with running state

Walk the array once and carry what you need: a running sum, the best value so far, a count. Examples: find the minimum, second maximum, maximum subarray.

Java
import java.util.Arrays;

public class Main {
    static int[] runningMax(int[] nums) {
        int[] out = new int[nums.length];
        int best = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            best = Math.max(best, nums[i]);
            out[i] = best;
        }
        return out;
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(runningMax(new int[]{3, 1, 4, 1, 5, 9, 2})));
    }
}
Output
[3, 3, 4, 4, 5, 9, 9]

2. Two pointers

Two indices move through the array: toward each other from both ends (sorted pair sums, reversing, max/min form) or side by side (merging two sorted arrays).

Java
public class Main {
    static boolean isPalindrome(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            if (nums[left] != nums[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    public static void main(String[] args) {
        System.out.println(isPalindrome(new int[]{1, 2, 3, 2, 1}) + " " + isPalindrome(new int[]{1, 2}));
    }
}
Output
true false

3. Read index and write index

Filter an array in place: a read index visits every element, and a write index marks where the next kept element goes. Examples: remove even integers, remove duplicates from a sorted array, move zeros to the end.

Java
import java.util.Arrays;

public class Main {
    static void moveZeros(int[] nums) {
        int write = 0;
        for (int read = 0; read < nums.length; read++) {
            if (nums[read] != 0) {
                int tmp = nums[write];
                nums[write] = nums[read];
                nums[read] = tmp;
                write++;
            }
        }
    }

    public static void main(String[] args) {
        int[] nums = {0, 1, 0, 3, 12};
        moveZeros(nums);
        System.out.println(Arrays.toString(nums));
    }
}
Output
[1, 3, 12, 0, 0]

4. Prefix and suffix computations

Precompute running totals from the left (prefix) or right (suffix) so a later question takes O(1). Examples: product of array except self, range sums, zero-sum subarray.

Java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] nums = {2, 4, 1, 3};
        int[] prefix = new int[nums.length + 1]; // prefix[i] = sum of nums[0..i)
        for (int i = 0; i < nums.length; i++) {
            prefix[i + 1] = prefix[i] + nums[i];
        }
        // sum of nums[1..3) = prefix[3] - prefix[1]
        System.out.println(Arrays.toString(prefix) + " " + (prefix[3] - prefix[1]));
    }
}
Output
[0, 2, 6, 7, 10] 5

5. Hashing

Remember values you have seen in a HashSet or HashMap to replace an inner search loop with an O(1) lookup. Examples: two sum, first non-repeating integer. The hashing section covers this pattern in depth.

Mistakes that cost time in Java

Integer overflow. int arithmetic wraps around silently when a result leaves the range of Integer.MIN_VALUE to Integer.MAX_VALUE (about plus or minus 2.1 billion). Accumulate sums and products in long, or use Math.addExact and Math.multiplyExact, which throw ArithmeticException on overflow.

Java
public class Main {
    public static void main(String[] args) {
        int big = Integer.MAX_VALUE;
        System.out.println(big + 1);                 // wraps to Integer.MIN_VALUE
        System.out.println((long) big + 1);          // widen before adding
        try {
            Math.addExact(big, 1);
        } catch (ArithmeticException e) {
            System.out.println("overflow detected");
        }
        System.out.println(Math.abs(Integer.MIN_VALUE)); // still negative
    }
}
Output
-2147483648
2147483648
overflow detected
-2147483648

Off-by-one bounds. The last valid index is length - 1. Prefer a half-open range [left, right) with right = length, or left < right with right = length - 1, and keep one convention per loop.

Sharing one array. int[] b = a; copies the reference, not the elements. Both names see the same data. Use a.clone() or Arrays.copyOf(a, a.length) for a copy. For int[][], clone() copies only the outer array, so copy each row as well.

Java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        int[] alias = a;
        int[] copy = a.clone();
        a[0] = 99;
        System.out.println(Arrays.toString(alias) + " " + Arrays.toString(copy));
    }
}
Output
[99, 2, 3] [1, 2, 3]

Removing while iterating. Calling list.remove(x) inside a for (int x : list) loop throws ConcurrentModificationException. Use list.removeIf(...), an Iterator with iterator.remove(), or a write index as shown above.

Comparing boxed values. Integer objects compare by value with equals. == compares references and gives the wrong answer for values outside the small cached range.