Nopeuden optimointi muistin kustannuksella JavaScriptissä
On tilanteita, joissa voitaisiin uhrata muistia suorituskyvyn parantamiseksi.
Katsotaanpa esimerkkiä. Seuraava koodi löytää ystävälliset luvut annetulta väliltä:
console.log(getFriendly(9000));
function getFriendly(range) {
let res = [];
for (let i = 1; i <= range; i++) {
for (let j = 1; j < range; j++) {
if (isFriendly(i, j)) {
res.push([i, j]);
}
}
}
return res;
}
function isFriendly(num1, num2) {
let sum1 = getSum(getOwnDivisors(num1));
let sum2 = getSum(getOwnDivisors(num2));
return sum1 == num2 && sum2 == num1;
}
function getOwnDivisors(num) {
let res = [];
for (let i = 1; i < num; i++) {
if (num % i === 0) {
res.push(i);
}
}
return res;
}
function getSum(arr) {
let sum = 0;
for (let elem of arr) {
sum += elem;
}
return sum;
}
Yllä oleva koodi ei ole optimaalinen.
Se tekee suuren määrän operaatioita
ja annetulla välillä 9000
selainsivu jäätyy yksinkertaisesti.
Tämän koodin ongelma on, että me
laskemme jokaiselle luvulle sen jakajien summan
hyvin monta kertaa, niin monta
kuin lukuja yhteensä tarkistetaan.
Tämä tarkoittaa, että meidän tapauksessamme
minkä tahansa luvun jakajien summa
löydetään 9000 kertaa.
Ei ole yllätys, että kaikki jäätyy.
Optimoidaan. Aluksi tehdään funktio, joka suoraan laskee jakajien summan, tallentamatta niitä taulukkoon:
function getOwnDivisorsSum(num) {
let sum = 0;
for (let i = 1; i < num; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
Nyt on aika uhrata muistia. Tehdään funktio, joka etukäteen kerran laskee kaikkien annetun välin lukujen jakajien summat ja tallentaa ne taulukkoon.
Funktion tuloksena on taulukko, jossa avaimena on luku (yksi vähemmän), ja arvona - sen jakajien summa. Toteutetaan funktiomme:
function getAllSum(range) {
let arr = [];
for (let i = 1; i <= range; i++) {
arr.push(getOwnDivisorsSum(i));
}
return arr;
}
Nyt ystävällisyyden tarkistamiseksi emme laske joka kerta uudelleen lukujen jakajien summaa, vaan yksinkertaisesti otamme jo lasketun taulukosta:
function getFriendly(range) {
let sums = getAllSum(range); // [1, 2, 6...]
let res = [];
for (let i = 0; i < sums.length; i++) {
for (let j = i; j < sums.length; j++) {
let sum1 = sums[i];
let sum2 = sums[j];
let num1 = i + 1;
let num2 = j + 1;
if (num1 == sum2 && num2 == sum1) {
res.push([num1, num2]);
}
}
}
return res;
}
Kootaan kaikki yhteen ja saadaan seuraava koodi:
console.log(getFriendly(9000));
function getFriendly(range) {
let sums = getAllSum(range);
let res = [];
for (let i = 0; i < sums.length; i++) {
for (let j = i; j < sums.length; j++) {
let sum1 = sums[i];
let sum2 = sums[j];
let num1 = i + 1;
let num2 = j + 1;
if (num1 == sum2 && num2 == sum1) {
res.push([num1, num2]);
}
}
}
return res;
}
function getAllSum(range) {
let arr = [];
for (let i = 1; i <= range; i++) {
arr.push(getOwnDivisorsSum(i));
}
return arr;
}
function getOwnDivisorsSum(num) {
let sum = 0;
for (let i = 1; i < num; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
Seuraava koodi löytää keskenään jaottomat luvut annetulta väliltä. Optimoi se:
console.log(getRelativelyPrime(10000));
function getRelativelyPrime(range) {
let res = [];
for (let i = 2; i <= range; i++) {
for (let j = 2; j < range; j++) {
if (isRelativelyPrime(i, j)) {
res.push([i, j]);
}
}
}
return res;
}
function isRelativelyPrime(num1, num2) {
let arr1 = getDivisors(num1);
let arr2 = getDivisors(num2);
let int = getIntersect(arr1, arr2);
if (int.length === 0) {
return true;
} else {
return false;
}
}
function getIntersect(arr1, arr2) {
let result = [];
for (let elem of arr1) {
if (arr2.includes(elem)) {
result.push(elem);
}
}
return result;
}
function getDivisors(num) {
let res = [];
for (let i = 2; i <= num; i++) {
if (num % i === 0) {
res.push(i);
}
}
return res;
}