Related
My solution is :
function printPairs($array, $sum) {
for ($i = 0; $i < count($array); $i++) {
$first = $array[$i];
for ($j = $i + 1; $j < count($array); $j++) {
$second = $array[$j];
if (($first + $second) == $sum) {
echo($first.','.$second);
}
}
}
}
complexity of this solution is O(n^2)
How can we improve this, what can we do better to improve this in PHP.
Answering this one question won't make you better at solving problems, you need to truly understand algorithms and their complexity. You can check out https://codility.com/programmers/ if you want to gain more experience in solving problems. There's many answers published for the various lessons, but I'd highly recommend you try to solve them yourself to the best of your ability before you go out seeking answers to the lessons/challenges.
So for this question you were given an array of integers and an integer that you needed to find the pairs.
You were probably also required to ensure that each number (index in array) was only used once.
So if you're input was [3,7,3] your pairs would just be [[3,7]] and not [[3,7],[7,3]]
Optimized solution
This solution would be considered O(2n) or just simplified to O(n) as it follows linear time.
function solution(array $arr, $int) {
$results = [];
$map = [];
# create a map of ints and how many you have
$size = sizeof($arr);
for($x = 0; $x < $size; $x++) {
$n = $arr[$x];
if (!array_key_exists($n, $map)) {
$map[$n] = 0;
}
$map[$n]++;
}
# loop through and find the pairs
$size = sizeof($map);
foreach($map as $n => $c) {
$w = $int - $n;
if (!array_key_exists($w, $map)) {
continue;
}
$map[$n]--;
$map[$w]--;
# edge case when $n === $w
if ($map[$n] < 0 || $map[$w] < 0) {
$map[$n]++;
$map[$w]++;
continue;
}
$results[] = [$n,$w];
}
return $results;
}
echo json_encode(solution([], 10)) . PHP_EOL;
echo json_encode(solution([1], 10)) . PHP_EOL;
echo json_encode(solution([10], 10)) . PHP_EOL;
echo json_encode(solution([0,10], 10)) . PHP_EOL;
echo json_encode(solution([5,5], 10)) . PHP_EOL;
echo json_encode(solution([-5,15], 10)) . PHP_EOL;
echo json_encode(solution([3,7,3], 10)) . PHP_EOL;
echo json_encode(solution([3,7,3,7,1,9], 10)) . PHP_EOL;
output
[]
[]
[]
[[0,10]]
[[5,5]]
[[-5,15]]
[[3,7]]
[[3,7],[7,3],[1,9]]
you can rewrite your function like this:
function printPairs($array, $sum) {
$map = [];
foreach ($array as $v) {
if (isset($map[$sum-$v])) {
echo $v . ',' . ($sum-$v) . "\n";
echo ($sum-$v) . ',' . $v . "\n";
}
$map[$v] = 1;
}
}
and average complexity will be O(N)
Let's say I have this array
$number = [2,1,4,3,6,2];
First pair the elements on an array by two's and find their difference
so this is the output in the first requirement
$diff[] = [1,1,4];
Second sum all the difference
this is the final output
$sum[] = [6];
Conditions:
the array size is always even
the first element in a pair is always greater than the second one, so their is no negative difference
What I've done so far is just counting the size of an array then after that I don't know how to pair them by two's. T_T
Is this possible in php? Is there a built in function to do it?
One line:
$number = [2,1,4,3,6,2];
$total = array_sum(array_map(function ($array) {
return current($array) - next($array);
}, array_chunk($number, 2)));
echo $total;
This should work fine:
<?
$number = array(2,1,4,3,6,2);
for($i=0;$i<count($number); $i+=2){
$dif[] = $number[$i] - $number[$i+1];
}
print_r($dif);
$sum = 0;
foreach ($dif as $item){
$sum += $item;
}
echo 'SUM = '.$sum;
?>
Working CODE
If you want all the different stages kept,
$numbers = [2,1,4,3,6,2];
$diff = [];
for($i=0,$c=count($numbers);$i<$c;$i+=2)
{
$diff[] = $numbers[$i]-$numbers[$i+1];
}
$sum = array_sum($diff);
Else, to just get the total and bypass the diff array:
$numbers = [2,1,4,3,6,2];
$total = 0;
for($i=0,$c=count($numbers);$i<$c;$i+=2)
{
$total += $numbers[$i]-$numbers[$i+1];
}
I have got this far it gives the required solution.
$arr = array(2,1,4,3,6,2);
$temp = 0;
$diff = array();
foreach ($arr as $key => $value) {
if($key % 2 == 0) {
$temp = $value;
}
else {
$diff[] = $temp - $value;
}
}
print_R($diff);
print 'Total :' . array_sum($diff);
Note : Please update if any one knows any pre-defined function than can sorten this code.
Please check and see if this works for you.
<?php
$sum=0;
$number = array(2,1,4,3,6,2);
for ($i=0;$i<=count($number);$i++) {
if ($i%2 == 1 ) {
$sum = $sum + $number[$i-1] - $number[$i];
}
}
print $sum;
?>
Well with your conditions in mind I came to the following
$number = [2,1,4,3,6,2];
$total = 0;
for($i = 0; $i < count($number); $i+=2) {
$total += $number[$i] - $number[$i + 1];
}
Try this one:
$number = array(2,1,4,3,6,2);
$diff = array();
$v3 = 0;
$i=1;
foreach($number as $val){
if ($i % 2 !== 0) {
$v1 = $val;
}
if ($i % 2 === 0) {
$v2 = $val;
$diff[] = $v1-$v2;
$v3+= $v1-$v2;
}
$i++;
}
print $v3;//total value
print_r($diff); //diff value array
I am trying to create a function which maps a recurring pattern of integers using an array.
As an example if I have a starting array of (0,1,3) and I know that I want to stop the pattern when I hit 15.
The pattern gets incremented by a fixed integer each time (lets say 4) so my final pattern should be..
0
1
3
4 (0 + 4)
5 (1 + 4)
7 (2 + 4)
8 (4 + 4)
9 (5 + 4)
11(7 + 4)
12(8 + 4)
13(9 + 4)
15(11+ 4)
Does anyone have any pointers on how this can be achieved?
My current implementation works but is stupidly inefficient which something like this...
$array = array(0,1,3);
$inc = 4;
$end = end($array);
$final = 15;
while($end < $final)
{
$tmp = array();
foreach($array AS $row)
{
$tmp = $row + $inc;
}
$array = merge($tmp, $array);
$end = end($array);
}
$array = array(0,1,3);
$inc = 4;
$final = 15;
$end = end($array);
while($end < $final)
{
$end += $inc;
$array[] = $end;
}
Or with a for loop:
$array = array(0,1,3);
$inc = 4;
$final = 15;
for($i = end($array) + $inc; $i <= $final; $i += $inc)
{
$array[] = $i;
}
Y'all are missing the fact that 4 is being added to the value in the array 2 keys back, not the last value.
This is the code you need (tested, and working)
$array = array(0,1,3);
$inc = 4;
$end = end($array);
$key = key($array);
$final = 15;
while ($end < $final) {
if ($array[$key-2] >= 0) {
$end = $array[$key-2] + $inc;
$array[] = $end;
$key++;
}
}
I also included in there a check to make sure the key being added to actually exists, though that may not be needed.
I assume that you want to have all the new values in the same array.
So:
//original array
$values = array(0, 1, 3);
//incremental value
$inc = 4;
//stop value
$stop = 15;
//set the index counter to the origin
$curr_index = 0;
//while the last value of the array is lower than the stop value
while($values[end($values)] < $stop)
{
//calculate the new value
$new_value = $values[$curr_index] + $inc;
//add the new value to the array
array_push($values, $new_value);
//update the index counter
$curr_index ++;
}
this code should work for any initial value in the array, any incremental value and any stop value.
<?php
function myArrayFunction(array $array, $inc = 4, $final = 15, $end = null)
{
if(!$end)
{
$end = end($array);
}
while($end < $final)
{
$end += $inc;
$array[] = $end;
}
return $array; //assume you're wanting $array back
}
This is minus any sort of testing or checking of injected values but you get the idea.
It would be better to know what you are trying to achieve here as the whole thing looks horribly overcomplicated, but...
$array = array(0,1,3);
$pattern = array();
$inc = 4;
$final = 15;
for ($base = 0; ; $base += $inc) {
foreach($array as $rem) {
if ($base + $rem > $final) break 2;
$pattern []= $base + $rem;
}
}
Alternatively,
$i = $v = 0;
while ($v < $final) {
$v = $pattern []= $pattern[$i++] + $inc;
}
(This assumes $final will be part of the pattern.)
If you can figure out how to calculate the number of elements will be in the array beforehand and assign that to $tum this should work.
<?php
$arr = array(0, 1, 3);
$inc = 4; // 6
$fin = 15; // 55
$num = count($arr);
$lum = 0;
$tum = 12; // 29
do
{
for($i = $lum; $i < $num; $i++)
{
$tar = $arr[$i] + $inc;
$arr[$tar] = $tar;
}
$lum = $num;
$num *= 2;
} while(end($arr) < $fin);
$arr = array_slice($arr, 0, $tum);
print_r($arr);
echo "\n";
?>
i'v been trying to implement merge sort under php. but seems unsuccessful :( couldn't find source of error. any kind of help is very much appreciated!
function merge_sort(&$input, $start, $end) {
if($start < $end) {
$mid = (int) floor($start + $end / 2);
merge_sort($input, $start, $mid);
merge_sort($input, $mid + 1, $end);
merge($input, $start, $mid, $end);
}
}
function merge(&$input, $p, $q, $r) {
$a = $q - $p + 1;
$b = $r - $q;
for($i = $p;$i <= $q;$i++) {
$arr1[] = $input[$i];
}
for($i = $q+1;$i <= $r;$i++) {
$arr2[] = $input[$i];
}
$c = $d = 0;
for($i = $p; $i <= $r; $i++) {
$s = $arr1[$c];
$t = $arr2[$d];
if($a && (($s <= $t) || !$b)) {
$input[$i] = $s;
$a--;$c++;
} else if($b) {
$input[$i] = $t;
$b--;$d++;
}
}
return true;
}
here's the info xdebug throw back:
Fatal error: Maximum function nesting level of '100' reached, aborting!
To reach a nesting level of 100 on a merge sort, you would need to have an input array of size 2^100(about 1e30), which is impossible. I suspect your recursion is incorrect. For instance, you wrote $start + $end / 2 instead of ($start + $end) / 2.
Set
xdebug.max_nesting_level=500
in my php.ini
Here's my working solution, feel free to compare...
/**
* #param array $items array to sort
* #param int $l left index (defaults to 0)
* #param int $r right index (defaults to count($items)-1)
*/
function mergeSort(&$items, $l = 0, $r = null)
{
if (!isset($r)) {
$r = count($items) - 1;
}
if ($l < $r) {
$m = floor(($r - $l) / 2) + $l;
mergeSort($items, $l, $m);
mergeSort($items, $m + 1, $r);
merge($items, $l, $m, $r);
}
}
/**
* #param array $items array to merge
* #param int $l left index
* #param int $m middle index
* #param int $r right index
*/
function merge(&$items, $l, $m, $r)
{
$itemsA = array_slice($items, $l, $m + 1 - $l);
$itemsB = array_slice($items, $m + 1, ($r + 1) - ($m + 1));
$a = 0;
$aCount = count($itemsA);
$b = 0;
$bCount = count($itemsB);
for ($i = $l; $i <= $r; $i++) {
if ($a < $aCount && ($b == $bCount || $itemsA[$a] <= $itemsB[$b])) {
$items[$i] = $itemsA[$a++];
} else {
$items[$i] = $itemsB[$b++];
}
}
}
$items = array(5,3,6,1,2,3,9,10,7,2,4,8);
mergeSort($items);
echo implode(',', $items) . "\n";
Outputs:
1,2,2,3,3,4,5,6,7,8,9,10
There is a maximum function nesting level of '100', and you have reached it. Your recursive function goes too deep.
From http://www.xdebug.org/docs/all_settings:
xdebug.max_nesting_level
Type: integer, Default value: 100
Controls the protection mechanism for infinite recursion protection. The value of this setting is the maximum level of nested functions that are allowed before the script will be aborted.
You are going too deep in your recursive function triggering this xdebug error. Try raising this limit and see if that helps.
Also, here is an interesting article about recursion and PHP: http://www.alternateinterior.com/2006/09/tail-recursion-in-php.html
PHP is not a good language for recursive algorithms. From the manual:
It is possible to call recursive
functions in PHP. However avoid
recursive function/method calls with
over 100-200 recursion levels as it
can smash the stack and cause a
termination of the current script.
If you need to do it in PHP, you'll probably have to find an iterative version of the algorithm. You've hit a hard-coded limit in the language.
Cosi dovrebbe funzionare!!!! www.dslpg.it
function merge ( &$a, $left, $center, $right ) { //left = p right = r center = q
$n1 = $center - $left + 1;
$n2 = $right - $center;
for ($i = 1; $i <= $n1; $i++) $L[$i] = $a[$left+$i-1];
for ($i = 1; $i <= $n2; $i++) $R[$i] = $a[$center+$i];
$L[$n1+1] = 99999;
$R[$n2+1] = 99999;
$i = 1;
$j = 1;
for ($k = $left; $k <= $right; $k++) {
if ($L[$i] <= $R[$j] ) {
$a[$k] = $L[$i];
echo $a[$k];
$i++;
}
else {
$a[$k] = $R[$j];
echo $a[$k];
$j++;
}
}
return $a;
}
function merge_sort ( &$a, $left, $right ) { //left = p right = r
if ( $left < $right ) {
$center = (int) floor(($left + $right) / 2 );
merge_sort ($a, $left, $center);
merge_sort ($a, $center+1, $right);
merge ($a, $left, $center, $right);
}
}
merge_sort ( $a, 1, $n );
Is there a way to make this faster?
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>', "\n";
next($data);
}
I do not like that I need to create new variables like $item.
<?php
$transport = array('foot', 'bike', 'car', 'plane');
foreach ($transport as $value) {
echo $value;
}
?>
If you don't want to create temporary variables, do it like this:
while (current($data))
{
echo '<ATTR>',current($data), '</ATTR>', "\n";
next($data);
}
However, I don't know if this will really make it any faster. They only way to tell would be with a profiler, but it is such a micro-optimization I doubt you will notice the difference.
The best way to speed up the loop would be to use a faster computer.
If all you're doing is the code above you could use an implode statement.
if (count($data) > 0) {
echo "<ATTR>".implode("</ATTR>\n<ATTR>", $data)."</ATTR>";
}
$nl = "\n";
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>',$nl;
next($data);
}
Store the newline character into a variable rather then having PHP parse the double quotation marks in every iteration.
I do a little bench to comprobe it.
<?php
$a = array();
for ($i = 0; $i < 100000; $i++) {
$a[] = $i;
}
$start = microtime(true);
foreach ($a as $k => $v) {
$a[$k] = $a[$k] + 1;
}
echo "foreach : ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => &$v) {
$v = $v + 1;
}
echo "foreach with cursor : ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
for ($i = 0; $i < count($a); ++$i) {
$a[$i] = $a[$i] + 1;
}
echo "for : ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
for ($i=0,$l=count($a);$i<$l;++$i) {
$a[$i] = $a[$i] + 1;
}
echo "for with cached count : ", microtime(true) - $start, " Seconds\n";
With results
foreach : 0.0039410591125488 Seconds
foreach with cursor : 0.00357985496521 Seconds
for : 0.0022602081298828 Seconds
for with cached count : 0.0020480155944824 Seconds
Hope this helps
You could do a foreach, but then you would be creating 2 new variables. Unless you just don't like the idea of assigning variables inside the while() clause.
foreach($data as $key => $value)
{
echo $key . " => ".$value;
}
Either way, you are going to need to create an actual variable.
What about this one :
function my_func($str) {
echo "<attr>{$str}</attr>\n";
}
array_map('my_func', $data);
(Should work, but I'm curious about it's speed compared with a foreach loop)
Or, if you are using PHP >= 5.3 (probably not your case, btw), you can use this one, based on a lambda function :
array_map(function ($item) {
echo "<attr>{$item}</attr>\n";
}, $data);
Almost the same, but without having to declare a function used only once in the program.