Оптимизация на ненужни масиви в PHP

Нека пред един програмист стои задачата да намери сумата на целите числа от 1 до 100000000.

Нашият програмист направи елегантно решение на тази задача, ето така:

php<?php
  echo array_sum(range(1, 100000000));
?>

Хубаво решение, нали? На един ред и всичко това. Но то не работи! Опитайте се да стартирате този код и той ще изведе на екрана грешка, че сте поискали твърде много оперативна памет.

Хм, 100000000 изглежда не е толкова много? Или е много? Нека пресметнем. Функцията range създава масив с 100000000 числа. Нека PHP заделя за число 2 байта - тогава за съхранението на нашия масив ще са необходими 200000000 байта, тоест нещо около 200 мегабайта оперативна памет.

Но всъщност ще е необходима много повече оперативна пама, защото в PHP има много големи режийни разходи при съхранението на масив. Например, при мен в текста на грешката се изписва, че се опитвам да заделя 4294967304 байта - нещо около 4 гигабайта!

Ясно вече защо се появява грешка - ние далеч надхвърлихме разрешения лимит на паметта.

Не е толкова трудно да пренапишем нашия скрипт по друг начин, почти без да консумира оперативна памет:

php<?php
  $sum = 0;
  
  for ($i = 1; $i <= 100000000; $i++) {
    $sum += $i;
  }
  
  echo $sum;
?>

А още по-добре използваме математическо решение:

php<?php
  $n = 1000000;
  $sum = $n * ($n + 1) / 2;
  echo $sum;
?>
Задание 1

Пред един програмист стои задачата да намери факториела на дадено число. Той я реши по следния начин:

php<?php
  $n = 100;
  echo array_product(range(1, $n));
?>

Обяснете какво не е наред с този код. Преправете кода на по-оптимален.

Задание 2

Пред един програмист стои задачата да намери броя на цифрите, с които могат да бъдат записани всички цели числа от 1 до 1000000. Той я реши по следния начин:

php<?php
  echo strlen(implode('', range(1, 1000000)));
?>

Обяснете какво не е наред с този код. Преправете кода на по-оптимален.

Задание 3

Пред един програмист стои задачата да намери броя на числата, които се делят без остатък на 7, намиращи се в даден интервал. Той я реши по следния начин:

php<?php
  $arr = [];
  
  for ($i = 0; $i <= 1000; $i++) {
    if ($i % 7 == 0) {
      $arr[] = $i;
    }
  }
  
  echo count($arr);
?>

Обяснете какво не е наред с този код. Преправете кода на по-оптимален.

Задание 4

Пред един програмист стои задачата да намери сумата на делителите на число. Той я реши по следния начин:

php<?php
  $num = 320;
  $divs = [];
  
  for ($i = 0; $i <= $num; $i++) {
    if ($num % $i == 0) {
      $divs[] = $i;
    }
  }
  
  echo array_sum($divs);
?>

Обяснете какво не е наред с този код. Преправете кода на по-оптимален.