Поиск дубликатов в массиве
Условие
Напишите программу, которая определяет, содержит ли массив дублирующиеся элементы.
Верните true, если какое-либо значение появляется в массиве хотя бы дважды, и false, если каждый элемент уникален.
Примеры
- [1, 2, 3, 1] → true
- [1, 2, 3, 4] → false
- [1, 1, 1, 3, 3, 4, 3, 2, 4, 2] → true
Требования
- Решение с HashSet за O(n)
- Альтернативное решение с сортировкой за O(n log n)
- Обработайте пустой массив и массив из одного элемента
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Поиск дубликатов в массиве
Это классическая задача на собеседованиях, проверяющая понимание структур данных и сложности алгоритмов. Рассмотрим несколько подходов с разной эффективностью.
Решение 1: HashSet (оптимальное) — O(n) время, O(n) память
Самое быстрое и популярное решение — использовать HashSet, который проверяет наличие элемента за O(1):
public class DuplicateFinder {
public static boolean containsDuplicate(int[] nums) {
if (nums == null || nums.length <= 1) {
return false;
}
HashSet<Integer> seen = new HashSet<>();
for (int num : nums) {
if (seen.contains(num)) {
return true;
}
seen.add(num);
}
return false;
}
public static void main(String[] args) {
System.out.println(containsDuplicate(new int[]{1, 2, 3, 1}));
System.out.println(containsDuplicate(new int[]{1, 2, 3, 4}));
System.out.println(containsDuplicate(new int[]{}));
System.out.println(containsDuplicate(new int[]{5}));
}
}
Как это работает:
- Проходим по каждому элементу массива
- Для каждого элемента проверяем, есть ли он уже в HashSet
- Если есть — возвращаем true (найден дубликат)
- Если нет — добавляем элемент в set и продолжаем
- Если прошли весь массив — возвращаем false
Решение 2: Сортировка — O(n log n) время
Альтернативный подход — отсортировать массив и сравнивать соседние элементы:
public class DuplicateFinderSorted {
public static boolean containsDuplicate(int[] nums) {
if (nums == null || nums.length <= 1) {
return false;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
}
Как это работает:
- Сортируем массив (O(n log n))
- Проходим по отсортированному массиву
- Если нашли два одинаковых соседних элемента — возвращаем true
- Иначе — false
Решение 3: Stream API (современный подход)
В Java 8+ можно использовать Stream API:
public class DuplicateFinderStream {
public static boolean containsDuplicate(int[] nums) {
if (nums == null || nums.length <= 1) {
return false;
}
return Arrays.stream(nums)
.boxed()
.collect(Collectors.toSet())
.size() < nums.length;
}
}
Решение 4: Оптимизированное
public class OptimizedDuplicateFinder {
public static boolean containsDuplicate(int[] nums) {
if (nums == null || nums.length <= 1) {
return false;
}
Set<Integer> seen = new HashSet<>(nums.length);
for (int num : nums) {
if (!seen.add(num)) {
return true;
}
}
return false;
}
}
Эта версия немного эффективнее, так как add() выполняет и проверку, и добавление одновременно.
Сравнение подходов
| Подход | Время | Память | Преимущества |
|---|---|---|---|
| HashSet | O(n) | O(n) | Быстрое, понятное, стандартное |
| Сортировка | O(n log n) | O(1) | Меньше памяти |
| Stream API | O(n) | O(n) | Функциональный подход |
Выводы
- На собеседовании предложите решение с HashSet — лучший компромисс
- Будьте готовы объяснить альтернативные подходы
- Учитывайте граничные случаи — пустой массив, один элемент, null
- Думайте о памяти — иногда сортировка может быть предпочтительнее
- Знайте сложность — O(n) vs O(n log n) важна при больших данных