Я просматривал этот пример, который, по-видимому, более быстрый способ сопоставления, чем использование нескольких циклов. Я видел объяснение здесь, но для меня это совершенно не имеет смысла.
Может кто-то пожалуйста сломать это для меня и для какой target - arr[i]
используется?
const arr = [7, 0, -4, 5, 2, 3];
const twoSum = (arr, target) => {
let map = {}
let results = [];
for (let i=0; i<arr.length; i++) {
if (map[arr[i]] !== undefined) {
results.push([map[arr[i]], arr[i]])
} else {
map[target - arr[i]] = arr[i];
}
}
return results;
}
console.log('twoSum = ', twoSum(arr, 5));
Кажется, что в объяснении, которое вы {7: -2, 5: 5}
есть ошибка: где говорится: "Наша новая пара ключей/значений 5: 5
Наша хэш-карта теперь содержит две записи: {7: -2, 5: 5}
." Новый ключ/значение (и это правильно сделано в коде) составляет 5: 0
.
Чтобы понять, как это работает, предположим, что наш массив равен [2, 6, 3]
а цель - 5
. Как только мы увидим 2
, мы хотели бы знать, имеет ли массив его партнера, который вместе суммирует до 5
.
x + 2 = 5
x = 5 - 2
x = 3
Итак, мы ищем 3
. Теперь объект карты JavaScript позволяет нам эффективно получать значение, если мы знаем его ключ. Таким образом, мы устанавливаем наш ключ на 3
- таким образом, если мы увидим 3
позже, мы можем быстро ответить. Помните, что мы еще не видели 3
. Мы просто установив ключ, чтобы быстро предупредить нас, если мы видим, что мы уже видели своего партнера, 2
, уже.
Теперь мы продолжаем движение по массиву. Мы проходим мимо 6
но на карте нет ключа 6
поэтому добавляем его к карте и продолжаем. Когда мы добираемся до 3
, мы говорим: "Ага!", Карта, имеющая 3
, предупреждает нас, что мы видели его партнера, который вместе суммирует до 5
. Мы подталкиваем результат, 3
(текущий arr[i]
) и значение, сохраненное на карте под клавишей 3
(map[arr[i]]
), которая была 2
мы видели ранее.
Вы даже можете сделать это быстрее, не сохраняя фактического значения, потому что вы ищете два значения, и одно известно, вы знаете другое.
const
arr = [7, 0, -4, 5, 2, 3],
twoSum = (arr, target) => {
let map = {},
results = [];
for (let i = 0; i < arr.length; i++) {
if (map[arr[i]]) { // straight check
results.push([target - arr[i], arr[i]]); // take delta
continue;
}
map[target - arr[i]] = true;
}
return results;
};
console.log('twoSum = ', twoSum(arr, 5));
Предположим, что цель равна t. Учитывая значение x в массиве, вы хотите знать, существует ли в массиве значение t - x, и в этом случае сумма равна t - x + x = t.
Итак, вы проходите через массив, чтобы отметить тот факт, что вы видите x в массиве, который вы отмечаете на карте t-x. Позже, когда вы встретите t-x в массиве, вы проверяете запись t-x на карте, и если она заполнена, то вы знаете, что раньше видели x, что означает, что у вас есть пара x и t-x. То, как я только что описал это, звучит как два цикла в массиве, но вы можете сделать эти две вещи только в одном цикле, и он работает одинаково.
Если запись в карте заполнена, то вы уже видели ее значение пары, если она не заполнена, вы отмечаете карту, чтобы увидеть, если вы столкнетесь с этим значением пары позже.
Алгоритм создает пары, исследуя обработанный объект с ранее просматриваемыми элементами.
Таким образом, для хранения ранее обнаруженных элементов требуется память, а также почему факторы map
входят в решение.
Пусть анализирует цикл в решении:
for (let i=0; i<arr.length; i++) {
if (map[arr[i]] !== undefined) {
results.push([map[arr[i]], arr[i]])
} else {
map[target - arr[i]] = arr[i];
}
}
Это эквивалентно следующему:
for ( let i = 0; i < arr.length; i++ ) {
// Any item in the array that not in the memory
// 1. should primarily be stored
// 2. such that it potential pair is stored as a key that mapped to a value which is the item
if ( map[ arr[ i ] ] === undefined ) {
map[ target - arr[ i ] ] = arr[ i ];
// Examine pairs only in iterations with odd numbered indices.
// Why? - For the first iteration, the memory is empty...
continue;
}
// this items pair is known, so store the pair in the result list
results.push( [ map[ arr[ i ] ], arr[ i ] ] );
}