From 4c1075b12462bf2bb86c756142e8590e857e2ba7 Mon Sep 17 00:00:00 2001
From: Marchenko Dmitriy
Date: Thu, 9 Oct 2025 13:47:32 +0500
Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=202=20?=
=?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ru/naumen/collection/task2/Task2.java | 93 ++++++++++++++++++-
.../java/ru/naumen/collection/task2/User.java | 34 ++++++-
2 files changed, 122 insertions(+), 5 deletions(-)
diff --git a/src/main/java/ru/naumen/collection/task2/Task2.java b/src/main/java/ru/naumen/collection/task2/Task2.java
index 83278f8..1d1f4a5 100644
--- a/src/main/java/ru/naumen/collection/task2/Task2.java
+++ b/src/main/java/ru/naumen/collection/task2/Task2.java
@@ -1,7 +1,9 @@
package ru.naumen.collection.task2;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Дано:
@@ -34,9 +36,94 @@ public class Task2
/**
* Возвращает дубликаты пользователей, которые есть в обеих коллекциях
+ *
+ * Принцип работы:
+ *
+ * - Вычисляется размер обеих коллекций и их отношение
+ * - Если отношение размеров больше 2, то меньшая коллекция
+ * преобразуется в HashSet, и по нему фильтруется большая коллекция
+ * - Если отношение размеров меньше или равно 2, то первая
+ * коллекция преобразуется в HashSet, и по нему фильтруется вторая коллекция
+ *
+ * Такой подход позволяет оптимизировать работу метода при значительной разнице в размерах
+ * коллекций, сохраняя при этом хорошую производительность при близких размерах.
+ *
+ * Временная сложность в худшем случае: O(n + m), где n и m - размеры коллекций.
+ * Пространственная сложность: O(min(n, m)) для хранения меньшей коллекции в HashSet.
+ *
+ * Таким образом, метод эффективно находит дубликаты пользователей в обеих коллекциях
+ * с оптимальной производительностью.
+ *
+ *
+ * Причина выбора коллекции HashSet:
+ * HashSet обеспечивает среднее время доступа O(1) для операций
+ * добавления и проверки наличия элемента (в случае правильно
+ * написанных {@link User#equals(Object)} и {@link User#hashCode()}), что делает его идеальным
+ * выбором для хранения пользователей при поиске дубликатов.
+ * Такой выбор коллекций обеспечивает оптимальную производительность и удобство
+ * при реализации метода поиска дубликатов.
+ *
+ * Примечание: Метод {@link #findCommonUsers} используется для фильтрации одной коллекции
+ * на основе наличия элементов в множестве, что обеспечивает эффективный поиск общих
+ * пользователей.
+ * @param collA коллекция A
+ * @param collB коллекция B
+ * @return список дубликатов
*/
public static List findDuplicates(Collection collA, Collection collB) {
- // TODO реализовать метод
- return null;
+ final double SIGNIFICANT_RATIO = 2.0;
+
+ double sizeA = collA.size();
+ double sizeB = collB.size();
+
+ if (sizeA == 0 || sizeB == 0) {
+ return List.of();
+ }
+
+ double ratio = Math.max(sizeA, sizeB) / Math.min(sizeA, sizeB);
+
+ if (ratio > SIGNIFICANT_RATIO) {
+ Collection smallerCol = sizeA > sizeB ? collB : collA;
+ Collection largerCol = sizeA > sizeB ? collA : collB;
+
+ Set smallerSet = new HashSet<>(smallerCol);
+
+ return findCommonUsers(largerCol, smallerSet);
+ } else {
+
+ Set setA = new HashSet<>(collA);
+
+ return findCommonUsers(collB, setA);
+ }
+ }
+ /**
+ * Находит общих пользователей между коллекцией и множеством
+ *
+ * Принцип работы:
+ * Берём коллекцию пользователей для проверки и фильтруем её,
+ * оставляя только тех пользователей, которые содержатся в множестве.
+ * Использование множества (Set) позволяет эффективно проверять наличие
+ * пользователя благодаря быстрому доступу по хешу.
+ *
+ * Временная сложность: O(n), где n - размер коллекции usersToCheck,
+ * так как для каждого пользователя выполняется операция проверки
+ * наличия в множестве, которая в среднем выполняется за O(1).
+ *
+ *
+ * Пространственная сложность: O(1), если не учитывать входные данные,
+ * так как дополнительная память используется только для хранения
+ * результата.
+ *
+ * Таким образом, метод эффективно находит общих пользователей
+ * между коллекцией и множеством с оптимальной производительностью.
+ *
+ * @param usersToCheck коллекция пользователей для проверки
+ * @param userSet множество пользователей для сравнения
+ * @return список общих пользователей
+ */
+ private static List findCommonUsers (Collection usersToCheck, Set userSet) {
+ return usersToCheck.stream()
+ .filter(userSet::contains)
+ .toList();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/ru/naumen/collection/task2/User.java b/src/main/java/ru/naumen/collection/task2/User.java
index 0803b0b..3c6560d 100644
--- a/src/main/java/ru/naumen/collection/task2/User.java
+++ b/src/main/java/ru/naumen/collection/task2/User.java
@@ -1,8 +1,16 @@
package ru.naumen.collection.task2;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* Пользователь
- *
+ *
+ * Класс с переопределёнными методами equals и hashCode для корректного сравнения объектов User.
+ * Метод equals сравнивает все три поля: username, email и passwordHash
+ * (используется Arrays.deepEquals для сравнения массивов).
+ * Метод hashCode генерирует хеш-код на основе всех трёх полей, используя Arrays.hashCode
+ * для массива passwordHash.
* @author vpyzhyanov
* @since 19.10.2023
*/
@@ -10,4 +18,26 @@ public class User {
private String username;
private String email;
private byte[] passwordHash;
-}
+
+ /**
+ * Сравнение объектов User
+ * @param o объект для сравнения
+ * @return true, если объекты равны, иначе false
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ User user = (User) o;
+ return Objects.equals(username, user.username) && Objects.equals(email, user.email) && Objects.deepEquals(passwordHash, user.passwordHash);
+ }
+
+ /**
+ * Получение хеш-кода объекта User
+ * @return
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(username, email, Arrays.hashCode(passwordHash));
+ }
+}
\ No newline at end of file