Hook: Interviewers love this one because it reveals whether you can replace a slow double-check with a clean one-pass solution.
Question: Find duplicate elements in an array.
Answer: The easiest reliable way in Java is to scan the array once and keep a Set of values you have already seen. If the current value is already in the set, that value is a duplicate, so you record it in a second set. This works for any integers, including negatives and zero, and it avoids the slow nested-loop approach.
Interview-Ready Answer: I would use a HashSet to track numbers I have already seen. As I iterate through the array, if add returns false, that means the value was already present, so I add it to a duplicates collection. I usually return a LinkedHashSet so each duplicate appears once and the encounter order is preserved. That gives me average O(n) time and O(n) extra space.
A duplicate element is any value that appears more than once in the array. In interviews, the key detail is whether you need unique duplicate values like [1, 2] or all repeated occurrences like [1, 1, 2]. The standard solution below returns each duplicated value once, which is what most questions expect.
Set called seen. A Set is a collection that does not allow duplicates.duplicates. This keeps only the values that repeat.seen. In Java, Set.add(x) returns true if x was new, and false if it was already there.add returns false, the number has been seen before, so put it into duplicates.duplicates. If you use LinkedHashSet, the results come out in the order the duplicates were first discovered.Memory Hook: Think of a party guest list: the first time a person arrives, they go into the lobby; the second time you see the same face, they go onto the blacklist. Seen once = lobby, seen twice = blacklist.
The brute-force way checks every pair of values, which is easy to imagine but slow: if the array has 10,000 items, that can mean about 50 million comparisons. The set-based solution checks each item once on average, so it is much faster and easier to explain cleanly at a whiteboard.
| Approach | Time | Space | When to use |
|---|---|---|---|
| HashSet scan | O(n) | O(n) | Fast, simple, interview default |
| Sort then scan | O(n log n) | Low extra space | When order does not matter and memory is tight |
| Frequency map | O(n) | O(n) | When you need counts too |
With a hash-based set, each lookup and insert is average O(1), so the whole scan is average O(n). In practice, if you store int values in HashSet<Integer>, Java must box them into Integer objects, which uses more memory than a raw primitive array. For one million distinct integers, the memory cost is often tens of megabytes, not just a few megabytes, because of object and hash table overhead.
HashSet does not guarantee order; use LinkedHashSet if the presentation order matters.O(n log n) time.Rule of thumb: if the question says duplicate elements and does not ask for counts or indices, the cleanest interview answer is usually seen set + duplicates set.
Real-World Story: Imagine a batch import service in an e-commerce platform that reads product IDs from a CSV before writing them to the catalog database. If the same product ID appears twice, the service may create duplicate records, confuse inventory counts, or trigger a unique-constraint error halfway through the import. A correct duplicate check lets the service reject the file early with a clear message like Duplicate product ID at row 183.
When this is misunderstood, the bug usually shows up as inconsistent totals: support sees one product listed twice, the log shows a database duplicate key error, and customers notice odd behavior like the same item appearing in search results multiple times. The real value of the duplicate-finding logic is not just correctness; it is making the failure obvious before bad data spreads through the system.
import java.util.*;
public class FindDuplicateElementsInArray {
// Returns each duplicated value once, in the order it was first detected as a duplicate.
public static Set<Integer> findDuplicates(int[] arr) {
if (arr == null) {
throw new IllegalArgumentException("Array must not be null");
}
Set<Integer> seen = new HashSet<>();
Set<Integer> duplicates = new LinkedHashSet<>(); // preserves encounter order
for (int value : arr) {
// add(...) tells us whether this is the first time we've seen the number.
if (!seen.add(value)) {
duplicates.add(value);
}
}
return duplicates;
}
// Useful when the interviewer asks for counts as well as duplicates.
public static Map<Integer, Integer> frequencyMap(int[] arr) {
if (arr == null) {
throw new IllegalArgumentException("Array must not be null");
}
Map<Integer, Integer> counts = new LinkedHashMap<>();
for (int value : arr) {
counts.put(value, counts.getOrDefault(value, 0) + 1);
}
return counts;
}
public static void main(String[] args) {
int[][] tests = {
{1, 2, 3, 1, 4, 2, 5, 2},
{},
{7, 7, 7},
{10, -1, 0, 10, -1},
{42}
};
for (int[] test : tests) {
System.out.println("Input: " + Arrays.toString(test));
System.out.println("Duplicates: " + findDuplicates(test));
System.out.println("Counts: " + frequencyMap(test));
System.out.println();
}
// Failure path: the method rejects null input instead of silently crashing later.
try {
findDuplicates(null);
} catch (IllegalArgumentException ex) {
System.out.println("Null input handled: " + ex.getMessage());
}
}
}
Follow-up & Tricky Questions:
Map<Integer, Integer> and increment the count for each value. Then any entry with count greater than 1 is a duplicate, and you also know exactly how many times it appears.LinkedHashSet instead of HashSet. A LinkedHashSet keeps insertion order, which is helpful when the interviewer wants results in a predictable sequence.HashSet return duplicates in the same order as the array? No. HashSet does not guarantee iteration order, so if order matters, use LinkedHashSet or sort the result later.Common Mistakes:
HashSet does not preserve order; choose LinkedHashSet when order matters.Memory Hook: First time in the lobby, second time on the blacklist. That is the whole mental model for the set-based solution.
Cheat Sheet:
seen set to track values already visited.seen.add(x) is false, x is a duplicate.LinkedHashSet when you want stable order.Practice Tasks:
Map<Integer, Integer>.String[] instead of int[].