Print all combination of sub range within a given array - php
I want to print all combination of sub range in an given array. I have an array of y number of elements in it from which I want to print all combination of contiguous sub range.
Constraint is : each sub range should have at least 2 elements and each element in sub range should be contiguous. It should share same border of each element.
For example, We have an array of 7 elements [11,12,13,14,11,12,13]
So, the total number of sub range combination will [7 * (7-1) /2] = 21
So, the Output will be something like this:
11,12
12,13
13,14
14,11
11,12
12,13
11,12,13
12,13,14
13,14,11
...
11,12,13,14 and so on (total 21 combination as per above array)
we should not print any combination which is not contiguous. example: [11,12,14] is not valid combination as it skips the element "13" in between.
I am able to print the combination with 2 elements but i am having difficulty in printing more then 2 elements combination.
Below is what I have tried so far.
$data=array("11","12","13","14","11","12","13");
$totalCount=count($data);
for($i=0;$i<$totalCount;$i++){
if(($i+1) < ($totalCount)){
echo "[".$data[$i].",".$data[$i+1]."]<br>";
}
}
You can do that:
$arr = [11,12,13,14,11,12,13];
function genComb($arr, $from = 1, $to = -1) {
$arraySize = count($arr);
if ($to == -1) $to = $arraySize;
$sizeLimit = $to + 1;
for ($i = $from; $i < $sizeLimit; $i++) { // size loop
$indexLimit = $arraySize - $i + 1;
for ($j = 0; $j < $indexLimit; $j++) { // position loop
yield array_slice($arr, $j, $i);
}
}
}
$count = 0;
foreach (genComb($arr, 2) as $item) {
echo implode(',', $item), PHP_EOL;
$count++;
}
echo "total: $count\n";
Casimir et Hippolyte was faster, but you can gain huge performance by processing each contiguous section independently:
function getCombos(&$data) {
$combos = array();
$count = count($data);
$i = 0;
while ($i < $count) {
$start = $i++;
while ($i < $count && $data[$i - 1] + 1 == $data[$i]) // look for contiguous items
$i++;
if ($i - $start > 1) // only add if there are at least 2
addCombos($data, $start, $i, $combos); // see other answer
}
return $combos;
}
Related
i want to count number of even,number of odd in php
I want to count number of even,number of odd.If there 2 even ,i count only one even,If there 2 odd i count only one number of odd <?php $myarray = array(5,5,0,1,2,1,1,6,1); for ($i = 0; $i < count($myarray); $i++) { echo "Index ", $i, ", value ", $myarray[$i], ": "; if ($myarray[$i] % 2 == 0) { echo "even\n"; } else { echo "odd\n"; } } ?> input =[5,5,0,1,2,1,1,6,1] output = 5 :1(total(5) odd one), 1:2 (total(1) odd two)
Use two variables that keep track of your odds and evens when you loop through your array. $my_array = array( 5, 5, 0, 1, 2, 1, 1, 6, 1 ); $odd = $even = 0; foreach ( $my_array as $number ) { $number % 2 == 0 ? $even++ : $odd++; } printf( 'Odd: %s | Even: %s', $odd, $even );
<?php $num = array(23,12,11,9,6,7,4,5,3); $n=count($num); $even = 0; $odd = 0; for( $i = 0 ; $i < $n; $i++) { if ($num[$i] & 1 == 1) $odd ++ ; else $even ++ ; } echo "Number of even elements = $even and Number of odd elements = $odd" ; ?>
Create counters $evens and odds. Then Loop through elements in array check if number is odd using Ternary Operator (condition) ? true : false;, and $num & 1 return true if number is odd. $nums = array(5,5,0,1,2,1,1,6,1); $odds = $evens = 0; foreach ($nums as $num) { $num & 1 ? ++$odds : ++$evens; } echo "Odds: $odds, Evens: $evens"; //Odds: 6, Evens: 3
Just count only number of odds, Because If we count number of Odds in array, It would be easy to know number of Evens by subtract number of elements in array with number of Odds $nums = array(5,5,0,1,2,1,1,6,1); $odds = 0; foreach ($nums as $num) { $odds += $num % 2; } $evens = count($nums)-$odds; echo "Odds: $odds, Evens: $evens"; //Odds: 6, Evens: 3
Can someone help me return a value?
I have created a loop which returns a random number between two values. Cool. But now I want the script to return the following value too: The number of unique numbers between two similar numbers. Example: 4 5 8 22 45 3 85 44 4 55 15 23 As you see there is a double which is the four and there are 7 numbers inbetween. So I would like the script to echo these numbers two so in this case it should echo 7 but if there are more doubles in the list it should echo all the numbers between certain doubles. This is what I have: for ($x = 0; $x <= 100; $x++) { $min=0; $max=50; echo rand($min,$max); echo "<br>"; } Can someone help me or guide me? I'm learning :) Thanks!
So You need to seperate script for three parts: getting randoms and save them to array (name it 'result'), analyze them, print (echo) results Simply - instead of printing every step of loop, save them to array(), exit loop, analyze every item with other, example: take i element of list check is i+j element is the same if is it the same - save j-i to second array() (name it 'ranges') And after this, print two arrays (named by me as 'result' and 'ranges') UPDATE: Here's solution, hope You enjoy: $result = array(); #variable is set as array object $ranges = array(); #same # 1st part - collecting random numbers for ($x = 0; $x < 20; $x++) { $min=0; $max=50; $result[] = rand($min,$max); #here's putting random number to array } $result_size = count($result); #variable which is containg size of $result array # 2nd part - getting ranges between values for ($i = 0; $i < $result_size; $i++) { for ($j = 0; $j < $result_size; $j++) { if($i == $j) continue; # we don't want to compare numbers with itself,so miss it and continue else if($result[$i] == $result[$j]) { $range = $i - $j; # get range beetwen numbers if($range > 0 ) # this is for miss double results like 14 and -14 for same comparing { $ranges[$result[$i]] = $range; } } } } #3rd part - priting results echo("RANDOM NUMBERS:<br>"); foreach($result as $number) { echo ("$number "); } echo("<br><br>RANGES BETWEEN SAME VALUES:<br>"); foreach($ranges as $number => $range) { echo ("For numbers: $number range is: $range<br>"); } Here's sample of echo ($x is set as 20): RANDOM NUMBERS: 6 40 6 29 43 32 17 44 48 21 40 2 33 47 42 3 22 26 39 46 RANGES BETWEEN SAME VALUES: For numbers: 6 range is: 2 For numbers: 40 range is: 9
Here is your fish: Put the rand into an array $list = array(); and $list[] = rand($min,$max); then process the array with two for loops. $min=0; $max=50; $list = array(); for ($x = 0; $x <= 100; ++$x) { $list[] = rand($min,$max); } print "<pre>";print_r($list);print "</pre>"; $ranges = array(); $count = count($list); for ($i = 0; $i < $count; ++$i) { $a = $list[$i]; for ($j = $i+1; $j < $count; ++$j) { $b = $list[$j]; if($a == $b) { $ranges[] = $j-$i; } } } print "<pre>";print_r($ranges);print "</pre>";
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
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
How can I check an array for consecutive times?
I have an array of qualified times from my database: $avail_times = array("9","11","12","13","15","16","17","18"); I want to display 4 consecutive values if they exist, if not I want to continue. For example in the above array, the only place where there are four consecutive numbers that properly follow the one before is 15,16,17,and 18 Thoughts? This may be a duplicate problem, but I have not found a solution. My situation is a bit different. I need to show only those numbers that are consecutive four or more times. This is what I have come up with, but it is not working properly: $avail_times = array("9","10","11","13","14","15","16","17","19","20","21","22"); for($i=1, $max = count($times) + 4; $i < $max; $i++) { if ($avail_times[$i] == $avail_times[$i + 1] - 1) { echo $avail_times[$i]; } }
This should do you: $avail_times = array("9","10","11","13","14","15","16","17","19","20","21","22"); $consec_nums = 1; for($i = 1; $i <count($avail_times); $i++) { if($avail_times[$i] == ($avail_times[$i - 1] + 1)) { $consec_nums++; if($consec_nums == 4) break; } else { $consec_nums = 1; } } if($consec_nums == 4) { echo "found: {$avail_times[$i-3]}, {$avail_times[$i-2]}, {$avail_times[$i-1]}, {$avail_times[$i]}\n"; } And a few notes: array indexing starts at 0, when your for loop starts with $i = 1, you are skipping the first element. Notice that while I start at $i=1, I am comparing $avail_times[$i] and $avail_times[$i-1] so I do cover $avail_times[0]. I don't know what you're doing with $max = count($times). You never define $times.