Pairwise function different calculation - php

i have this function:
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
for ($i = 0; $i < $n; $i++)
{
// absolute difference between
// consecutive numbers
$diff = abs($arry[$i] - $arry[$i + 1]);
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);
The problem are that im not expecting this output
becouse first number of array (20) is my commission
and the other numbers are my parents commission (10,10,50).
So basically i need to output like this: (0,0,30)
becouse i take 20 of commission,
first parent not take nothing becouse are less of my commission (10)
second parent not take nothing becouse are less of my commission (10)
and only last parent take 30 becouse are greater than my commission (50 - 20 my commission).
Thanks in advance

Since your first element of the array is your commission and the others are the the commissions of parents, and since it seems that you don't want to include your commission in the result array, you can do something like this:
function pairwiseDifference($arry)
{
$n = count($arry);
$diff = 0;
$result = array();
$myComm = $arry[0]; // your commision
for ($i = 1; $i < $n; $i++)
{
$diff = 0; // set $diff to 0 as default
if($myComm < $arry[$i]) // if your commision < parent commision
$diff = $arry[$i] - $myComm;
echo $diff." ";
array_push($result, $diff);
}
return $result;
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
$diffArray = pairwiseDifference($arry);
echo $diffArray[0]; // prints 0
echo $diffArray[1]; // prints 0
echo $diffArray[2]; // prinst 30

To tweak the logic according to your code, there would be only 3 modifications.
Create a $max variable and assign it the value of $arry[0].
Make difference as 0 if current max is greater than current one, else take the difference.
Calculate the new max again using max() function.
Snippet:
<?php
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
$max = $arry[0]; // new addition
for ($i = 1; $i <= $n; $i++) // new modification <= n instead of < n
{
// absolute difference between
// consecutive numbers
$diff = $max < $arry[$i] ? $arry[$i] - $max : 0; // new modification
$max = max($max, $arry[$i]); // new modification
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);

Related

Optimizing Find nearest sum of numbers in array to a given number

Say I have an array [10000,5000,1000,1000] and I would like to find the closest sum of numbers to a given number. Sorry for the bad explanation but here's an example:
Say I have an array [10000,5000,1000,1000] I want to find the closest numbers to, say 6000.
Then the method should return 5000 and 1000
another example : we want the closest to 14000 , so then he should return 10000 and 5000
I've tried with code below, here is working one but if the $desiredSum and $numbers array is big. it's running so slow until php execution timeout
$numbers = array(
10000,5000,1000,1000
);
$desiredSum = 6000;
$minDist = null;
$minDist_I = null;
// Iterate on every possible combination
$maxI = pow(2,sizeof($numbers));
for($i=0;$i<$maxI;$i++) {
if(!(($i+1) % 1000)) echo ".";
// Figure out which numbers to select in this
$sum = 0;
for($j=0;$j<sizeof($numbers);$j++) {
if($i & (1 << $j)) {
$sum += $numbers[$j];
}
}
$diff = abs($sum - $desiredSum);
if($minDist_I === null || $diff < $minDist) {
$minDist_I = $i;
$minDist = $diff;
}
if($diff == 0) break;
}
$chosen = array();
for($j=0;$j<sizeof($numbers);$j++) {
if($minDist_I & (1 << $j)) $chosen[] = $numbers[$j];
}
echo "\nThese numbers sum to " . array_sum($chosen) . " (closest to $desiredSum): ";
echo implode(", ", $chosen);
echo "\n";
Anyone can help me out ?
<?php
function coinChange($numbers,$desiredSum){
sort($numbers);
$set = [];
$set[0] = [];
for($i = $numbers[0];$i <= $desiredSum;++$i){
foreach($numbers as $index => $current_number){
if($i >= $current_number && isset($set[$i - $current_number])){
if(isset($set[$i - $current_number][$index])) continue;
$set[$i] = $set[$i - $current_number];
$set[$i][$index] = true;
break;
}
}
}
if(count($set) === 0){
return [0,[]];
}
if(isset($set[$desiredSum])){
return [
$desiredSum,
formatResult($numbers,array_keys($set[$desiredSum]))
];
}else{
$keys = array_keys($set);
$nearestSum = end($keys);
$sum = 0;
$rev_numbers = array_reverse($numbers);
$result = [];
foreach($rev_numbers as $number){
$sum += $number;
$result[] = $number;
if($sum > $nearestSum && abs($nearestSum - $desiredSum) > abs($sum - $desiredSum)){
$nearestSum = $sum;
break;
}else if($sum > $nearestSum && abs($nearestSum - $desiredSum) < abs($sum - $desiredSum)){
$result = formatResult($numbers,array_keys($set[$nearestSum]));
break;
}
}
return [
$nearestSum,
$result
];
}
}
function formatResult($numbers,$keys){
$result = [];
foreach($keys as $key) $result[] = $numbers[$key];
return $result;
}
print_r(coinChange([10000,5000,1000,1000],14000));
print_r(coinChange([10000,5000,1000,1000],13000));
print_r(coinChange([100000,100000,100000,100000,100000,100000,50000,50000,50000,50000,10000,10000,500,500,500,1000,1000],250000));
print_r(coinChange([100000,100000,100000,100000,100000,100000,50000,50000,50000,50000,10000,10000,500,500,500,1000,1000],179999));
Demo: https://3v4l.org/hBGeW
Algorithm:
This is similar to coin change problem.
We first sort the numbers.
Now, we iterate from minimum number in the array to the desired sum.
Inside it, we iterate through all elements in the array.
Now, we can make $i(which is a sum) only if we have made sum $i - $current_number. If we have the previous one, then we add $current_number to our collection for sum $i.
Two Scenarios:
If we can make the exact sum, then we return the result as is.
If we can't, then are 2 possibilities:
We would already have nearest sum possible in our $set which would be the last entry. We keep them in a variable.
Now, the nearest sum could also be higher than the desired sum. So, we get the larger sum and check if it's nearer than nearest smallest sum and then compare both and return the result.
Result format:
Let's take the below sample output:
Array
(
[0] => 15000
[1] => Array
(
[0] => 10000
[1] => 5000
)
)
It simply means that the first index is the nearest sum possible and array at 2nd index is all elements it took from $numbers to make that sum.

How to print correct multiplication of big number in PHP

I was trying to print multiplication of big numbers and they are resulting in float type scientific number.
var_dump((double)('290287121823'*'290287121823'));
I tried the function number_format and preg_replace to remove all ','. But after number_format the result is not correct.
Used following code:
preg_replace("/,/", "", (number_format(('290287121823'*'290287121823'))));
Output received: 84266613096281242861568
Expected correct output: 84266613096281243382112
The large numbers are computed digits by digits. Like we learn at school (see Long multiplication).
ex:
// 17
// x 27
// ----
// 119
// + 34
// -----
// = 459
Here is a function (which should be optimized) but shows you the principle.
echo bn_mul('17', '27'), PHP_EOL; // 459
echo bn_mul('157', '27'), PHP_EOL; // 4239
echo bn_mul('1234', '6627'), PHP_EOL; // 8177718
echo bn_mul('23958233', '5830'), PHP_EOL; // 139676498390
echo bn_mul('290287121823', '290287121823'), PHP_EOL; // 84266613096281242843329
Implementation:
function bn_mul($n2, $n1) {
$l1 = strlen($n1);
$l2 = strlen($n2);
$rows = [];
for ($idx1 = $l1 - 1 ; $idx1 >= 0 ; $idx1--) {
// get digit
$d1 = substr($n1, $idx1, 1) ;
$carry = 0; // reset carry
$row = []; // store digit of $d1 x each digits of $n2
// prepend 0 (10 * num rows)
for ($x=0 ; $x<count($rows) ; $x++) $row[] = 0;
for ($idx2 = $l2 - 1 ; $idx2 >= 0 ; $idx2--) {
// get digit
$d2 = substr($n2, $idx2, 1) ;
// multiplication of digit 1 x digit 2 + current carry
$r = $d1 * $d2 + $carry;
$carry = 0;
// compute carry
if ($r >= 10) {
$carry = substr($r, 0, -1);
$r = substr($r, -1);
}
$row[] = $r ;
}
if ($carry) $row[] = $carry;
$rows[] = $row ;
}
// Sum digits of rows
$total = [] ;
$carry = 0 ;
for ($x=0;$x < count(end($rows)) ; $x++){
$tot = $carry;
$carry = 0;
foreach ($rows as $row){
if (isset($row[$x])) $tot += $row[$x] ;
}
while ($tot >= 10) {
$tot -= 10;
$carry++;
}
$total[$x] = $tot;
}
return strrev(implode($total));
}
You should keep in mind that even if PHP is NOT typesafe, there are types in the background.
When you look up the documentation you'll find out, that floating points only have a precision up to 14 digits. Therefore, all trailing numbers are "cut off". The magnitude remains and it will print in scientific format but you can't really know what's "below" that 14 digits. Therefore, your try to convert the result is doomed to fail in the first place.
Example:
12345678910111213
^^^ get's cut off

Print all combination of sub range within a given array

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;
}

Simple PHP program requires less time to execute

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)

Finding the difference between 2 dates and iterating an image based on the difference

Ive managed to loop through a table and get the difference in days between 2 dates adjacent to each other in the table.
Multiple entries have the same date, i have it now that when that date changes, it displays an image however i want it to display the image as many times as the difference in date
$sql = mysql_query("SELECT * FROM Films_Info")
or die(mysql_error());
$last_value = null;
while ($row = mysql_fetch_assoc($sql)) {
if (!is_null($last_value)) {
$a = new DateTime($row['FilmRelease']);
echo "<p>".$row['FilmName']."</p>";
$interval = $a->diff(new DateTime($last_value));
//echo $interval->format('%d days');
$i = 0;
}
$howManydays = $interval->days;
for ( $i; $howManydays; $i++) {
echo "<img src=\"day.jpg\" />";
$howManydays = 0;
}
$last_value = $row['FilmRelease'];
}
for ( $i = 0; $i < $howManydays; $i++) The second is a conditional statement telling when the loop should stop.
The first section in the for loop where it says $i = 0 initialized the variable $i to 0 and then tests the condition $i < $howManydays.
Let's say $howManydays equals 1. That means 0 < 1, so the loop will perform.
At the end of the loop, the third section is called ($i++), so $i is incremented and now equals 1. The second section is called again to test conditions $i < $howManydays which is asking if 1<1 which it's not, so the loop will exit.
So if $howManydays is greater than 0, the loop should happen the integer amount that is in $howManydays.
You will want to remove $howManydays = 0; within the for loop, if you don't want it to only fire once.
The for loop
for ( $i = 0; $i < $howManydays; $i++){
// ...
}
is somewhat equivalent to the while loop:
$i = 0;
while ( $i < $howManydays ){
// ...
$i++;
}
http://php.net/manual/en/control-structures.for.php for more information
In your code above, you should also check if interval was set. You should probably just do an if rather than a while, if only need one interval.
you could just do a simple division on the interval and print out the image that many times
$last_value_u = $last_value->format('U');
$a_u = $a->format('U');
$interval = $a_u - $last_value_u;
$image_count = intval($interval/86400);
for($i=0;$i<$image_count;$i++)
echo "<p><img src=\"day.jpg\" /></p>";
Update
An alternative option would be to loop through the interval:
for($i=$last_value_u;$i<$a_u;)
{
if(intval(($a_u - $i)/86400) == X)
{
// run special code for specific day
}
else
{
// run code for every other day
}
$i+=86400;
}

Categories