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.
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)));
}
}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.
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}));
}
}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] trueArrays.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:
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));
}
}[9, 5, 3, 1] 4 truelist.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.
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})));
}
}[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).
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}));
}
}true false3. 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.
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));
}
}[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.
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]));
}
}[0, 2, 6, 7, 10] 55. 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.
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
}
}-2147483648
2147483648
overflow detected
-2147483648Off-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.
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));
}
}[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.
