Simple PHP program requires less time to execute - php

i had applied for a job recently and the requirement was to complete a test and then interview
2 questions were given for test which was very simple and i did it successfully but still i was told that i have failed the test because the script took more than 18 seconds to complete execution. here is the program i dont understand what else i could do to make it fast. although i have failed the test but still wants to know else i could do?
Program language is PHP and i had to do it using command line input
here is the question:
K Difference
Given N numbers , [N<=10^5] we need to count the total pairs of numbers that have a difference of K. [K>0 and K<1e9]
Input Format:
1st line contains N & K (integers).
2nd line contains N numbers of the set. All the N numbers are assured to be distinct.
Output Format:
One integer saying the no of pairs of numbers that have a diff K.
Sample Input #00:
5 2
1 5 3 4 2
Sample Output #00:3
Sample Input #01:
10 1
363374326 364147530 61825163 1073065718 1281246024 1399469912 428047635 491595254 879792181 1069262793
Sample Output #01:
0
Note: Java/C# code should be in a class named "Solution"
Read input from STDIN and write output to STDOUT.
and this is the solution
$fr = fopen("php://stdin", "r");
$fw = fopen("php://stdout", "w");
fscanf($fr, "%d", $total_nums);
fscanf($fr, "%d", $diff);
$ary_nums = array();
for ($i = 0; $i < $total_nums; $i++) {
fscanf($fr, "%d", $ary_nums[$i]);
}
$count = 0;
sort($ary_nums);
for ($i = $total_nums - 1; $i > 0; $i--) {
for ($j = $i - 1; $j >= 0; $j--) {
if ($ary_nums[$i] - $ary_nums[$j] == $diff) {
$count++;
$j = 0;
}
}
}
fprintf($fw, "%d", $count);

Your algorithm's runtime is O(N^2) that is approximately 10^5 * 10^5 = 10^10. With some basic observation it can be reduced to O(NlgN) which is approximately 10^5*16 = 1.6*10^6 only.
Algorithm:
Sort the array ary_nums.
for every i'th integer of the array, make a binary search to find if ary_nums[i]-K, is present in the array or not. If present increase result, skip i'th integer otherwise.
sort($ary_nums);
for ($i = $total_nums - 1; $i > 0; $i--) {
$hi = $i-1;
$low = 0;
while($hi>=$low){
$mid = ($hi+$low)/2;
if($ary_nums[$mid]==$ary_nums[$i]-$diff){
$count++;
break;
}
if($ary_nums[$mid]<$ary_nums[$i]-$diff){
$low = $mid+1;
}
else{
$hi = $mid-1;
}
}
}
}

I got the same question for my technical interview. I wonder if we are interviewing for the same company. :)
Anyway, here is my answer I came up with (after the interview):
// Insert code to get the input here
$count = 0;
sort ($arr);
for ($i = 0, $max = $N - 1; $i < $max; $i++)
{
$lower_limit = $i + 1;
$upper_limit = $max;
while ($lower_limit <= $upper_limit)
{
$midpoint = ceil (($lower_limit + $upper_limit) / 2);
$diff = $arr[$midpoint] - $arr[$i];
if ($diff == $K)
{
// Found it. Increment the count and break the inner loop.
$count++;
$lower_limit = $upper_limit + 1;
}
elseif ($diff < $K)
{
// Search to the right of midpoint
$lower_limit = $midpoint + 1;
}
else
{
// Search to the left of midpoint
$upper_limit = $midpoint - 1;
}
}
}
#Fallen: Your code failed for the following inputs:
Enter the numbers N and K: 10 3
Enter numbers for the set: 1 2 3 4 5 6 7 8 9 10
Result: 6
I think it has to do with your calculation of $mid (not accounting for odd number)

Related

Find the highest product in 4 directions in a matrix

I got this challenge to find the highest product of 4 consecutive numbers on a 20x20 matrix of integers.
The numbers are read line by line from a file separated by a space.
The products can be in horizontal, vertical and diagonal in both directions
My "solution" gives the wrong answer.
EDIT: I've updated the code to work without file input and added sample data; also fixed one of my mistakes that were pointed out in the comments
$data = [
[89,32,92,64,81,2,20,33,44,1,70,75,39,62,76,35,16,77,22,27],
[53,11,6,95,41,51,31,59,8,23,19,13,61,91,48,69,84,52,66,24],
[93,72,85,97,21,79,56,5,45,3,65,30,83,87,43,7,34,0,4,14],
[29,17,49,9,82,90,55,67,15,63,54,94,12,28,96,37,58,98,86,78],
[74,40,50,60,26,99,80,18,10,46,36,68,25,57,47,71,42,73,88,38],
[50,22,6,26,18,53,52,5,46,2,89,77,83,48,4,58,45,28,84,81],
[49,82,31,14,69,17,91,54,34,40,0,33,30,95,60,44,29,24,85,16],
[27,11,76,39,15,86,92,74,99,59,94,12,55,57,38,96,47,32,78,75],
[51,20,87,42,62,41,7,35,23,21,71,25,67,97,80,90,88,64,13,70],
[19,9,56,43,68,93,65,98,36,3,61,63,10,72,8,73,1,66,79,37],
[22,58,52,12,3,41,28,72,42,74,76,64,59,35,85,78,14,27,53,88],
[46,80,5,96,7,68,61,69,67,34,36,40,82,26,75,50,29,91,10,2],
[30,39,19,48,33,93,1,45,66,98,0,23,62,25,51,71,56,77,24,21],
[79,87,94,60,8,32,13,65,4,92,73,9,31,37,17,84,15,90,86,20],
[95,6,81,70,47,16,44,83,49,43,55,54,18,63,38,11,97,89,99,57],
[95,78,64,58,7,17,53,28,74,86,6,12,54,85,21,94,16,69,25,68],
[13,20,41,97,1,2,80,30,0,84,67,45,93,96,82,92,62,33,18,44],
[60,77,31,70,76,36,59,38,15,3,91,46,65,73,49,11,8,35,5,52],
[61,66,79,40,26,72,89,71,75,99,22,9,43,32,14,81,98,88,87,83],
[10,4,23,19,56,57,51,47,50,27,90,63,42,29,24,55,48,37,39,34]
];
$matrix = [];
//maximums in possible directions
$maxes = [0, 0, 0, 0];
//while ($line = trim(fgets(STDIN))) {
while ($line = current($data)) {
//the horizontal maxes can be calculated while loading
//$array = explode(" ", $line);
$array = $line;
$hMax = array_product(array_slice($array, 0, 4));
for ($i = 1; $i < (count($array)-4); $i++) {
$max = array_product(array_slice($array, $i, 4));
if($max > $hMax) {
$hMax = $max;
}
}
if ( $hMax > $maxes[0] ) {
$maxes[0] = $hMax;
}
$matrix[] = $array;
next($data);
}
// the last 3 rows can be skipped
for($i = 0; $i < (count($matrix)-4); $i++) {
for ($j = 0; $j < (count($matrix[$i])-1); $j++) {
$vMax = 1; // vertical
$dlMax = 1; // diagonal left
$drMax = 1; // diagonal rigth
for ($k = 0; $k < 5; $k++) {
$vMax *= $matrix[$i + $k][$j];
if ( $j < (count($matrix[$i]) - 4) ) {
$drMax *= $matrix[$i + $k][$j + $k];
}
if ( $j > 3 ) {
$dlMax *= $matrix[$i + $k][$j - $k];
}
}
if ( $maxes[1] < $vMax ) $maxes[1] = $vMax; // the index used to be 1 - my first mistake
if ( $maxes[2] < $dlMax ) $maxes[2] = $dlMax; // the index used to be 1 - my first mistake
if ( $maxes[3] < $drMax ) $maxes[3] = $drMax; // the index used to be 1 - my first mistake
}
}
sort($maxes);
echo end($maxes).PHP_EOL;
Where did my approach go wrong, and how can it be sped up?
Are there any math tricks that can be applied here (besides checking for zeros)?
EDIT: the solution that the code gives for the current data is 4912231320 is it correct?
I've found 2 major errors, and now the result is a plausible 67352832
I'm considering it solved for that reason, but if anyone comes up with some math trick that simplifies or makes it faster I'll give up the accepted answer.
The first mistake was
for ($k = 0; $k < 5; $k++) {
It should've been
for ($k = 0; $k < 4; $k++) {
since we are only counting 4 numbers at once, thats why the result was so large compared to 10^8
The second was
if ( $j > 3 ) {
which should've been
if ( $j > 2 ) {
which will now include one more diagonal possibility
We can consider the four directions a bottom- or right-most cell can be the last of in a sequence. If m[i][j][k][d] is the highest total for a sequence of length k coming from direction d, then:
m[i][j][1][d] = data[i][j] for all d
m[i][j][k]['E'] = data[i][j] * m[i][j - 1][k - 1]['E']
m[i][j][k]['NE'] = data[i][j] * m[i - 1][j - 1][k - 1]['NE']
m[i][j][k]['N'] = data[i][j] * m[i - 1][j][k - 1]['N']
m[i][j][k]['NW'] = data[i][j] * m[i - 1][j + 1][k - 1]['NW']
If we traverse north to south, east to west, the needed cells should have already been calculated, and, clearly, we're looking for
max(m[i][j][4][d])
for all i, j, d

generating same number with the given length

I have this math assignment that I should make into code.
I've tried all I thought of but I couldn't find a solution.
All this should be done without using php functions, only math operations.
You can use while, for, and such...
So I have number for example 9
Now I should create number of the length 9 which would be 999999999
If I had, for example, number 3, then the result should be 333.
Any ideas?
$gen = -1;
while($highest > 0) {
$gen = $highest + ($highest * 10);
$highest = $highest - 1;
}
echo $gen;
Here is a method that does not build a string; it uses pure math. (There will be many, many ways to do this task)
$x=9;
$result=0;
for($i=$x; $i; --$i){ // this looping expression can be structured however you wish potato-potatoe
$result+=$x*(10**($i-1)); // x times (10 to the power of (i-1))
}
echo $result;
// 999999999
*note: ** acts like pow() if you want to look it up.
Late edit: here is a clever, little loopless method (quietly proud). I am only calling range() and foreach() to demo; it is not an integral component of my method.
Demo: https://3v4l.org/GIjfG
foreach(range(0,9) as $n){
// echo "$n -> ",(integer)(1/9*$n*(10**$n)-($n/10)),"\n";
// echo "$n -> ",(1/9*$n*(10**$n)-(1/9*$n)),"\n";
// echo "$n -> ",(int)(1/9*10**$n)*$n,"\n";
// echo "$n -> ",(int)(10**$n/9)*$n,"\n";
echo "$n -> ",(10**$n-1)/9*$n,"\n";
}
Output:
0 -> 0
1 -> 1
2 -> 22
3 -> 333
4 -> 4444
5 -> 55555
6 -> 666666
7 -> 7777777
8 -> 88888888
9 -> 999999999
1/9 is the hero of this method because it generates .111111111(repeating). From this float number, I am using 10**$n to "shift" just enough 1s to the left side of the decimal point, then multiplying this float number by $n, then the float must be converted to an integer to complete.
Per #axiac's comment, the new hero is 10**$n-1 which generates a series of nines to the desired length (no float numbers). Next divide the nines by nine to generate a series of ones which becomes the perfect multiplier. Finally, multiply the series of ones and the input number to arrive at the desired output.
There are two operations you need to accomplish:
given a number $number, append the digit $n to it;
repeat operation #1 some number of times ($n times).
Operation #1 is easy:
$number = $number * 10 + $n;
Operation #2 is even easier:
for ($i = 0; $i < $n; $i ++)
What else do you need?
Initialization of the variable used to store the computed number:
$number = 0;
Put them in order and you get:
// The input digit
// It gives the length of the computed number
// and also its digits
$n = 8;
// The number we compute
$number = 0;
// Put the digit $n at the end of $number, $n times
for ($i = 0; $i < $n; $i ++) {
$number = $number * 10 + $n;
}
// That's all
If intval() is accepted:
$result = '';
$input = 9;
for($i=0; $i < $input; $i++){
$result .= $input;
}
$result = intval($result);
else:
$result = 0;
$input = 9;
for($i=0; $i < $input; $i++){
$factor = 1;
for($j = 0; $j < $i; $j++){
$factor *= 10;
}
$result += $input * $factor;
}
=>
9 + 90 + 900 + 9000 + 90000...

Possible combinations of binary

The problem statement is as following:
A particular kind of coding which we will refer to as "MysteryCode" is a binary system of encoding in which two successive values, differ at exactly one bit, i.e. the Hamming Distance between successive entities is 1. This kind of encoding is popularly used in Digital Communication systems for the purpose of error correction.
LetMysteryCodes(N)represent the MysteryCode list for N-bits.
MysteryCodes(1) = 0, 1 (list for 1-bitcodes,in this order)
MysteryCodes(2) = 00, 01, 11, 10 (list for 2-bitcodes,in this order)
MysteryCodes(3) =000, 001, 011, 010,110, 111, 101, 100 (list for 3-bitcodes,in this order)
There is a technique by which the list of (N+1) bitcodescan be generated from (N)-bitcodes.
Take the list of N bitcodesin the given order and call itList-N
Reverse the above list (List-N), and name the new reflected list: Reflected-List-N
Prefix each member of the original list (List-N) with 0 and call this new list 'A'
Prefix each member of the new list (Reflected-List-N) with 1 and call this new list 'B'
The list ofcodeswith N+1 bits is the concatenation of Lists A and B.
A Demonstration of the above steps: Generating the list of 3-bitMysteryCodesfrom 2-BitMysteryCodes
2-bit list ofcodes:00, 01, 11, 10
Reverse/Reflect the above list:10, 11, 01, 00
Prefix Old Entries with 0:000, 001, 011, 010
Prefix Reflected List with 1:110, 111, 101, 100
Concatenate the lists obtained in the last two steps:000, 001, 011, 010, 110, 111, 101, 100
Your Task
Your task is to display the last N "MysteryCodes" from the list of MysteryCodes for N-bits. If possible, try to identify a way in which this list can be generated in a more efficient way, than iterating through all the generation steps mentioned above.
More efficient or optimized solutions will receive higher credit.
Input Format
A single integer N.
Output Format
N lines, each of them with a binary number of N-bits. These are the last N elements in the list ofMysteryCodesfor N-bits.
Input Constraints 1 = N = 65
Sample Input 1
1
Sample Output 1
1
Explanation for Sample 1
Since N = 1, this is the (one) last element in the list ofMysteryCodesof 1-bit length.
Sample Input 2
2
Sample Output 2
11
10
Explanation for Sample 2 Since N = 2, these are the two last elements in the list ofMysteryCodesof 2-bit length.
Sample Input 3
3
Sample Output 3
111
101
100
$listN = 25;
$bits = array('0','1');
//check if input is valid or not
if(!is_int($listN))
{
echo "Input must be numeric!";
}
if($listN >= 1 && $listN <=65){
if($listN == 1){
echo '1'; exit;
}
ini_set('memory_limit', -1);
for($i=1; $i<=($listN - 1); $i++){
$reverseBits = array_reverse($bits);
$prefixBit = preg_filter('/^/', '0', $bits);
$prefixReverseBits = preg_filter('/^/', '1', $reverseBits);
$bits = array_merge($prefixBit, $prefixReverseBits);
unset($prefixBit, $prefixReverseBits, $reverseBits);
}
$finalBits = array_slice($bits, -$listN);
foreach($finalBits as $k=>$v){
echo $v."\n";
}
}
else{
echo "Invalid input!";
}
I have tried above solution, but didnt worked for input greater than 20.
for eg. If the input is 21, I got "Couldnt allocate memory" error.
It will be great if somebody figure out the optimized solutions...
The numbers follow a pattern which I transformed to below code.
Say given number is N
then create a N x N matrix and fill it's first column with 1's
and all other cells with 0's
Start from rightmost column uptil 2nd column.
For any column X start from bottom-most row and fill values like below:
Fill 2^(N - X + 1)/2 rows with 0's.
Fill 2^(N - X + 1) rows with 1's and then 0's alternatively.
Repeat step 2 till we reach topmost row.
Print the N x N matrix by joining the values in each row.
<?php
$listN = 3;
$output = [];
for ($i = 0; $i < $listN; $i++) {
$output[$i] = [];
for ($j = 0; $j < $listN; $j++) {
$output[$i][$j] = 0;
}
}
$output[$listN - 1][0] = 1;
for ($column = 1; $column < $listN; $column++) {
$zeroFlag = false;
for ($row = $listN - 1; $row >= 0;) {
$oneZero = 1;
if (!$zeroFlag) {
for ($k = 1; $k <= pow(2, $column) / 2 && $row >= 0; $k++) {
$output[$row][$listN - $column] = 0;
$row--;
$zeroFlag = true;
}
}
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
$oneZero = 0;
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
}
}
for ($i = 0; $i < $listN; $i++) {
$output[$i][0] = 1;
}
for ($i = 0; $i < $listN; $i++) {
print(join('', $output[$i]));
print("\n");
}

How to generate random numbers to produce a non-standard distributionin PHP

I've searched through a number of similar questions, but unfortunately I haven't been able to find an answer to this problem. I hope someone can point me in the right direction.
I need to come up with a PHP function which will produce a random number within a set range and mean. The range, in my case, will always be 1 to 100. The mean could be anything within the range.
For example...
r = f(x)
where...
r = the resulting random number
x = the mean
...running this function in a loop should produce random values where the average of the resulting values should be very close to x. (The more times we loop the closer we get to x)
Running the function in a loop, assuming x = 10, should produce a curve similar to this:
+
+ +
+ +
+ +
+ +
Where the curve starts at 1, peeks at 10, and ends at 100.
Unfortunately, I'm not well versed in statistics. Perhaps someone can help me word this problem correctly to find a solution?
interesting question. I'll sum it up:
We need a funcion f(x)
f returns an integer
if we run f a million times the average of the integer is x(or very close at least)
I am sure there are several approaches, but this uses the binomial distribution: http://en.wikipedia.org/wiki/Binomial_distribution
Here is the code:
function f($x){
$min = 0;
$max = 100;
$curve = 1.1;
$mean = $x;
$precision = 5; //higher is more precise but slower
$dist = array();
$lastval = $precision;
$belowsize = $mean-$min;
$abovesize = $max-$mean;
$belowfactor = pow(pow($curve,50),1/$belowsize);
$left = 0;
for($i = $min; $i< $mean; $i++){
$dist[$i] = round($lastval*$belowfactor);
$lastval = $lastval*$belowfactor;
$left += $dist[$i];
}
$dist[$mean] = round($lastval*$belowfactor);
$abovefactor = pow($left,1/$abovesize);
for($i = $mean+1; $i <= $max; $i++){
$dist[$i] = round($left-$left/$abovefactor);
$left = $left/$abovefactor;
}
$map = array();
foreach ($dist as $int => $quantity) {
for ($x = 0; $x < $quantity; $x++) {
$map[] = $int;
}
}
shuffle($map);
return current($map);
}
You can test it out like this(worked for me):
$results = array();
for($i = 0;$i<100;$i++){
$results[] = f(20);
}
$average = array_sum($results) / count($results);
echo $average;
It gives a distribution curve that looks like this:
I'm not sure if I got what you mean, even if I didn't this is still a pretty neat snippet:
<?php
function array_avg($array) { // Returns the average (mean) of the numbers in an array
return array_sum($array)/count($array);
}
function randomFromMean($x, $min = 1, $max = 100, $leniency = 3) {
/*
$x The number that you want to get close to
$min The minimum number in the range
$max Self-explanatory
$leniency How far off of $x can the result be
*/
$res = [mt_rand($min,$max)];
while (true) {
$res_avg = array_avg($res);
if ($res_avg >= ($x - $leniency) && $res_avg <= ($x + $leniency)) {
return $res;
break;
}
else if ($res_avg > $x && $res_avg < $max) {
array_push($res,mt_rand($min, $x));
}
else if ($res_avg > $min && $res_avg < $x) {
array_push($res, mt_rand($x,$max));
}
}
}
$res = randomFromMean(22); // This function returns an array of random numbers that have a mean close to the first param.
?>
If you then var_dump($res), You get something like this:
array (size=4)
0 => int 18
1 => int 54
2 => int 22
3 => int 4
EDIT: Using a low value for $leniency (like 1 or 2) will result in huge arrays, since testing, I recommend a leniency of around 3.

how to find the sum of all the multiples of 3 or 5 below 1000 in php, issue?

i have an small issue with the way this problem is resolved.
some would say: println((0 /: ((0 until 1000).filter(x => x % 3 == 0 || x % 5 == 0))) (_+_)) is the solution witch adds to 233168
my way was to do:
$maxnumber = 1000;
for ($i = 3; $i < $maxnumber; $i += 3)
{
$t += $i;
echo $i.',';
}
echo '<br>';
for ($j = 5; $j < $maxnumber; $j += 5)
{
$d += $j;
echo $j.',';
}
echo '<br>';
echo $t;
echo '<br>';
echo $d;
echo '<br>';
echo $t+$d;
this will give me :
3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249,252,255,258,261,264,267,270,273,276,279,282,285,288,291,294,297,300,303,306,309,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357,360,363,366,369,372,375,378,381,384,387,390,393,396,399,402,405,408,411,414,417,420,423,426,429,432,435,438,441,444,447,450,453,456,459,462,465,468,471,474,477,480,483,486,489,492,495,498,501,504,507,510,513,516,519,522,525,528,531,534,537,540,543,546,549,552,555,558,561,564,567,570,573,576,579,582,585,588,591,594,597,600,603,606,609,612,615,618,621,624,627,630,633,636,639,642,645,648,651,654,657,660,663,666,669,672,675,678,681,684,687,690,693,696,699,702,705,708,711,714,717,720,723,726,729,732,735,738,741,744,747,750,753,756,759,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819,822,825,828,831,834,837,840,843,846,849,852,855,858,861,864,867,870,873,876,879,882,885,888,891,894,897,900,903,906,909,912,915,918,921,924,927,930,933,936,939,942,945,948,951,954,957,960,963,966,969,972,975,978,981,984,987,990,993,996,999
5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,255,260,265,270,275,280,285,290,295,300,305,310,315,320,325,330,335,340,345,350,355,360,365,370,375,380,385,390,395,400,405,410,415,420,425,430,435,440,445,450,455,460,465,470,475,480,485,490,495,500,505,510,515,520,525,530,535,540,545,550,555,560,565,570,575,580,585,590,595,600,605,610,615,620,625,630,635,640,645,650,655,660,665,670,675,680,685,690,695,700,705,710,715,720,725,730,735,740,745,750,755,760,765,770,775,780,785,790,795,800,805,810,815,820,825,830,835,840,845,850,855,860,865,870,875,880,885,890,895,900,905,910,915,920,925,930,935,940,945,950,955,960,965,970,975,980,985,990,995
$t - 166833
$d - 99500
and total:
266333
why am i wrong?
Some numbers are multiples of both 3 and 5. (Your algorithm adds these numbers to the total twice.)
Because 6 * 5 == 30 and 10 * 3 == 30, you're adding the some numbers up twice.
$sum = 0;
$i = 0;
foreach(range(0, 999) as $i) {
if($i % 3 == 0 || $i % 5 == 0) $sum += $i;
}
Because you double-count numbers that are multiple of both 3 and 5, i.e. multiples of 15.
You can account for this naively by subtracting all multiples of 15.
for ($j = 15; $j < $maxnumber; $j += 15)
{
$e += $j;
echo $j.',';
}
$total = $total - $d;
In your case, if it is 15, you will add the number twice.
Try this:
$t = 0;
$d = 0;
for ($i = 0; $i <= $maxnumber; $i++){
if ($i % 3 == 0)
$t+= $i;
else if ($i % 5 == 0)
$d += $i;
}
echo $t.'<br>'.$d;
I think that in your code, if a number is a multiple of 3 and 5, it is added twice. Take 15 for example. It's in your list of multiples of 3 and in the list of multiples of 5. Is this the behaviour you want?
One of the best approach to this solution (to achieve optimum time complexity), run an Arithmetic Progression series and find the number of terms in all series by using AP formula: T=a+(n-1)d, then find sum by : S=n/2[2*a+(n-1)d]
where : a=first term ,n=no. of term , d=common deference, T=nth term
The code solution below has been implemented to suit the question above - so the values 3 and 5 are hard-coded. However, the function can modified such that values are passed in as variable parameters.
function solution($number){
$val1 = 3;
$val2 = 5;
$common_term = $val1 * $val2;
$sum_of_terms1 = calculateSumofMulitples($val1,$number);
$sum_of_terms2 = calculateSumofMulitples($val2,$number);
$sum_of_cterms = calculateSumofMulitples($common_term,$number);
$final_result = $sum_of_terms1 + $sum_of_terms2 - $sum_of_cterms;
return $final_result;
}
function calculateSumofMulitples($val, $number)
{
//first, we begin by running an aithmetic prograssion for $val up to $number say N to get the no of terms [using T=a +(n-1)d]
$no_of_terms = (int) ($number / $val);
if($number % $val == 0) $no_of_terms = (int) ( ($number-1)/$val ); //since we are computing for a no of terms below N and not up to/exactly/up to N. if N divides val with no remainder, use no of terms = (N-1)/val
//second, we compute the sum of terms [using Sn = n/2[2a + (n-1)d]
$sum_of_terms = ($no_of_terms * 0.5) * ( (2*$val) + ($no_of_terms - 1) * $val );
// sum of multiples
return $sum_of_terms;
}
You can run a single loop checking whether the number is multiple of 3 OR 5:
for ($i = 0; $i < $maxnumber; $i++)
{
if($i%3 || $i%5){
$t += $i;
echo $i.',';}
}
I think the original code is not including numbers which are multiples of both 3 and 5 in the total: if the test for multiple of 3 matches, it takes that and goes on.
If you total the multiples of 15 up to 1000, you get 33165, which is exactly the difference between your total, 266333, and the original total, 233168.
Here's my solution to the question:
<?php
$sum = 0;
$arr = [];
for($i = 1; $i < 1000; $i++){
if((int)$i % 3 === 0 || (int)$i % 5 === 0)
{
$sum += $i;
array_push($arr,$i);
}
}
echo $sum;
echo '<br>';
print_r($arr);//Displays the values meeting the criteria as an array of values

Categories