A sebesség optimalizálása memóriával JavaScriptben
Vannak helyzetek, amikor feláldozhatjuk a memóriát a teljesítmény javítása érdekében.
Nézzünk egy példát. A következő kód megtalálja a barátságos számokat egy adott tartományban:
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;
}
A fenti kód nem optimális.
Nagyon sok műveletet végez,
és a megadott 9000 tartományig
a böngésző oldala egyszerűen lefagy.
Ennek a kódnak a problémája az, hogy
minden számhoz sokszor számoljuk ki
az osztóinak összegét, annyiszor,
ahány számot ellenőrzünk.
Ez azt jelenti, hogy esetünkben
bármely szám osztóinak összege
9000 alkalommal kerül kiszámításra.
Nem meglepő, hogy minden lefagy.
Optimalizáljunk. Először készítsünk egy függvényt, amely közvetlenül kiszámolja az osztók összegét anélkül, hogy tömbbe mentené őket:
function getOwnDivisorsSum(num) {
let sum = 0;
for (let i = 1; i < num; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
Itt az ideje feláldozni a memóriát. Készítsünk egy függvényt, amely előre egyszer kiszámítja az összes szám osztóinak összegét a megadott tartományból, és elmenti azokat egy tömbbe.
A függvényünk egy tömböt fog visszaadni, amelyben a kulcs a szám (egyel kisebb), az érték pedig az osztóinak összege lesz. Valósítsuk meg a függvényünket:
function getAllSum(range) {
let arr = [];
for (let i = 1; i <= range; i++) {
arr.push(getOwnDivisorsSum(i));
}
return arr;
}
Most a barátságosság ellenőrzéséhez már nem minden alkalommal számoljuk ki a számok osztóinak összegét, hanem egyszerűen kivesszük a már kiszámított értéket a tömbből:
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;
}
Vegyük össze mindet, és megkapjuk a következő kódot:
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;
}
A következő kód megtalálja a relatív prím számokat egy adott tartományból. Optimalizálja le:
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;
}