Вернуть число из списка, ближайшее к systemId

60. Найти число, ближайшее к systemId

Условие задачи:
Метод getSystemSecretNumber() получает список чисел через NumberGenerator и должен вернуть число, ближайшее к systemId.

Расстояние между числами определяется как модуль их разности. Если два числа находятся на одинаковом расстоянии, возвращается первое встретившееся.

Код:

@Service
@RequiredArgsConstructor
public class ClosestNumberFinderService {

    /*
     * Бин подключается из библиотеки.
     * Доступен только интерфейс:
     *
     * public interface NumberGenerator {
     *     List<Integer> loadNumbers();
     * }
     */
    private final NumberGenerator generator;

    private final int systemId = 10;

    public Integer getSystemSecretNumber() {
        List<Integer> numbers = generator.loadNumbers();
        return findClosestNumber(numbers, systemId);
    }

    private Integer findClosestNumber(
            List<Integer> numbers,
            int systemId
    ) {
        // код тут
    }
}

Примеры:

[3, 5, 7, 9, 12, 15], systemId = 10 → 9
[1, 8, 11, 20], systemId = 10 → 11
[10, 20, 30], systemId = 10 → 10
[-5, 0, 6], systemId = 4 → 6

Спойлеры к решению

Подсказки
💡 Храни ближайшее найденное число и минимальное расстояние.
💡 Для каждого элемента вычисляй модуль разности с systemId.
💡 Для расчёта расстояния используй long, чтобы избежать переполнения int.
💡 Пустой список и null нужно обработать отдельно.

Решение
@Service
@RequiredArgsConstructor
public class ClosestNumberFinderService {

    private final NumberGenerator generator;

    private final int systemId = 10;

    public Integer getSystemSecretNumber() {
        List<Integer> numbers = generator.loadNumbers();
        return findClosestNumber(numbers, systemId);
    }

    private Integer findClosestNumber(
            List<Integer> numbers,
            int systemId
    ) {
        if (numbers == null || numbers.isEmpty()) {
            throw new IllegalArgumentException(
                    "Numbers must not be empty"
            );
        }

        Integer closestNumber = null;
        long minimumDifference = Long.MAX_VALUE;

        for (Integer number : numbers) {
            if (number == null) {
                continue;
            }

            long difference = Math.abs(
                    (long) number - systemId
            );

            if (difference < minimumDifference) {
                minimumDifference = difference;
                closestNumber = number;
            }
        }

        if (closestNumber == null) {
            throw new IllegalArgumentException(
                    "Numbers must contain at least one value"
            );
        }

        return closestNumber;
    }
}

Метод проходит по списку один раз и обновляет результат, когда находит число с меньшим расстоянием до systemId.

Строгое сравнение < сохраняет первое встретившееся число при одинаковом расстоянии.

Временная сложность — O(n), дополнительная память — O(1).