Найти все пары, которые суммируются с целевым значением

1

Я просматривал этот пример, который, по-видимому, более быстрый способ сопоставления, чем использование нескольких циклов. Я видел объяснение здесь, но для меня это совершенно не имеет смысла.

Может кто-то пожалуйста сломать это для меня и для какой 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));
  • 0
    Это аккуратное решение! Я бы не подумал об этом.
Теги:
algorithm

4 ответа

0
Лучший ответ

Кажется, что в объяснении, которое вы {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 мы видели ранее.

1

Вы даже можете сделать это быстрее, не сохраняя фактического значения, потому что вы ищете два значения, и одно известно, вы знаете другое.

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));
  • 0
    Спасибо Нине за более быстрый подход, но я хочу понять, как пример, который я опубликовал, работает больше, чем другой подход.
1

Предположим, что цель равна t. Учитывая значение x в массиве, вы хотите знать, существует ли в массиве значение t - x, и в этом случае сумма равна t - x + x = t.

Итак, вы проходите через массив, чтобы отметить тот факт, что вы видите x в массиве, который вы отмечаете на карте t-x. Позже, когда вы встретите t-x в массиве, вы проверяете запись t-x на карте, и если она заполнена, то вы знаете, что раньше видели x, что означает, что у вас есть пара x и t-x. То, как я только что описал это, звучит как два цикла в массиве, но вы можете сделать эти две вещи только в одном цикле, и он работает одинаково.

Если запись в карте заполнена, то вы уже видели ее значение пары, если она не заполнена, вы отмечаете карту, чтобы увидеть, если вы столкнетесь с этим значением пары позже.

  • 0
    Спасибо Шон, но для меня это не имеет смысла. т - х + х = т
0

Алгоритм создает пары, исследуя обработанный объект с ранее просматриваемыми элементами.

Таким образом, для хранения ранее обнаруженных элементов требуется память, а также почему факторы 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 ] ] );
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню