DEV Community

faangmaster
faangmaster

Posted on

Two Sum

Классическая задача на алгоритмы с собеседования.

Задача.

Дан массив целых чисел. Надо найти пару чисел в массиве, сумма которых равна заданному числу. В качестве результата вернуть индексы этих элементов. Можно считать, что такая пара есть всегда и только одна.
Например:
Для массива nums = [2, 11, 15, 7], target = 9
Ответ: [0,3]
Т.к. nums[0] + nums[3] = 2 + 7 = 9

Решение.

На ум сразу приходит очевидное решение: перебрать все пары чисел и проверить, что их сумма равна заданному числу.

public int[] twoSum(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        for (int j = 0; j < nums.length; j++) {
            if (i != j && nums[i] + nums[j] == target) {
                return new int[]{i, j};
            }
        }
    }
    return new int[] {-1, -1};
}

Enter fullscreen mode Exit fullscreen mode

Такое решение работает за O(n^2) по времени, т.к. у нас два вложенных цикла. Space Complexity O(1), т.к. никакой дополнительной памяти мы не используем, за исключением нескольких переменных примитивного типа.

Это решение можно улучшить до линейного при помощи hash-таблицы.
Будем в цикле идти по массиву и кэшировать все числа массива, которые мы уже видели, в этой hash-таблице.

Далее, чтобы получить заданную сумму, нам нужно чтобы
nums[i] + второе число из массива = target
Т.е. для текущего индекса i это другое число в массиве должно быть:
второе число из массива = target - nums[i].
Проверим, не встречалось ли нам уже это число раньше при проходе массива. Сделать это можно просто проверив, не хранится ли оно в нашей hash-таблице.

Назовем это второе число complementaryNumber.

Когда код решения:

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        //Вычисляем значение нашего второго дополнительного числа 
        //до пары
        int complementaryNumber = target - nums[i];
        //Если мы его уже видели - мы нашли нашу пару
        if (map.containsKey(complementaryNumber)) {
            return new int[] {i, map.get(complementaryNumber)};
        }
        //кэшируем числа и их индексы, которые мы ранее видели в 
        //массиве
        map.put(nums[i], i);
    }
    return new int[]{-1, -1};
}
Enter fullscreen mode Exit fullscreen mode

Это решение работает на O(n) (линейное время). Space Complexity при этом тоже O(n), т.к. мы еще храним значения из массива в hash-таблице, размер которой будет пропорционален размеру массива.

У этой задачи есть множество вариаций. Например, можно ли еще улучшить это решение если массив отсортирован? Или найти не индексы, а сами числа. Или найти тройки или четверки чисел, сумма, которых равна заданному значению.

Разборы этих вариаций будут в будущем на моем канале.

Top comments (0)