Сделайте функцию, которая будет находить пары дружественных чисел в заданном промежутке и возвращать их в виде двухмерного массива вида

Прохожу курс по JS и попал на задачу:

Сделайте функцию getFreindly, которая будет находить пары дружественных чисел в промежутке (1, 3000) и возвращать их в виде двухмерного массива.

Вроде бы решил данную задачу так:

function getOwnDivisors(num) {
    let arr = [];

    for (let i = 1; i < num; i++) {
        if (num % i === 0) {
            arr.push(i);
        }
    }

    return arr;
};

console.log(getOwnDivisors(220));

function getSum(num) {
    let sum = 0;

    for (let item of num) {
        sum += item;
    }

    return sum;
};

console.log(getSum(getOwnDivisors(220)));


function isFriendly(num1, num2) {
    let sum1 = getSum(getOwnDivisors(num1));
    let sum2 = getSum(getOwnDivisors(num2));

    if (sum1 == num2 && sum2 == num1) {
        return true;
    }
    return false;
};

console.log(isFriendly(220, 284));

function getFriendly(start, end) {
    let arr = [];

    for (let i = start; i < end; i++) {
        for (let j = i + 1; j < end; j++) {
            if (isFriendly(i, j)) {
                arr.push([i, j]);
            }
        }
    }
    return arr;
};

console.log(getFriendly(1, 3000));

Но, данное решение прям очень нагружает пк, и выводит результат слишком долго, хотел узнать способ решение данной задачи, что бы код обрабатывался как можно быстрее.Либо посоветуйте куда обратить внимание.

Как понял я, все из-за getFriendly() в большом дипазоне, слишком много нужно перебирать цикл в цикле.

Больше всего интересует как изменить именно функцию getFriendly(), не трогая остальной код.

Спасибо)


Ответы (1 шт):

Автор решения: KoVadim

Я не настоящий js сварщик, но чуточку могу. Посмотрим в код - видим один паттерн - конструкцию getSum(getOwnDivisors(num)). явно нужно заменить на одну функцию

function getAll(num) {
  return getSum(getOwnDivisors(num));
}

и исправляем рядом функцию isFriendly

function isFriendly(num1, num2) {
    let sum1 = getAll(num1);
    let sum2 = getAll(num2);

    return (sum1 == num2 && sum2 == num1);
};

Запускаем и проверяем, что работает также медленно (у меня от 1 до 1000 было порядка 3 секунд)

теперь переписываем функцию getAll

var mm = new Map();
function getAll(num) {
  var v = mm.get(num);
  if (v !== undefined) {
    return v;
  }
  v = getSum(getOwnDivisors(num));
  mm.set(num, v);
  return v;
}

(да, я знаю, я сделал глобальную мапу, но я по другому не умею в js). Теперь снова запускаем и получаем что то в районе 0.1 секунды. Уже лучше. Запускаем до 10000 - полторы секунды. лучше. Но хочется ещё лучше. Я буквально чуточку выжал, делая цикл до num/2.

Но хочется ведь быстрее и попроще. Переписал функцию немного через массив (не верил, что так работает)

var mm = [];
function getAll(num) {
  var v = mm[num];
  if (v !== undefined) {
    return v;
  }
  v = getSum(getOwnDivisors(num));
  mm[num] = v;
  return v;
}

и скорость стала просто чудесной - 0.4 секунды для диапазона до 10000. Думаю, это нормально.

→ Ссылка