2

The question is asked by hackerrank and i got the solution, but there is a problem in the solution at last test cases.

The question is below.

1 <= $n <= 65

Following is 1-bit sequence (n = 1)

0 1

Output

1

Following is 2-bit sequence (n = 2)

00 01 11 10

Output

11 10

Following is 3-bit sequence (n = 3)

000 001 011 010 110 111 101 100

Output

111 101 100

Following is 4-bit sequence (n = 4)

 0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 
  1110 1010 1011 1001 1000

Output

1010 1011 1001 1000

Solution Example

following are steps for generating the 3-bit Gray code list from the list of 2-bit Gray code list.

  • L1 = {00, 01, 11, 10} (List of 2-bit Gray Codes)
  • L2 = {10, 11, 01, 00} (Reverse of L1)
  • Prefix all entries of L1 with ‘0’, L1 becomes {000, 001, 011, 010}
  • Prefix all entries of L2 with ‘1’, L2 becomes {110, 111, 101, 100}
  • Concatenate L1 and L2, we get {000, 001, 011, 010, 110, 111, 101, 100}

The First Solution is given below.(based on solution example above)

but the given solution below will not work after 22,23 numbers. The memory allocation error occurred.

<?php

$input = 2;

$list_array = ["0","1"];
$reverse_array = array_reverse($list_array);

for($i = 1; $i < $input; $i++ )
{
    for($j = 0; $j < sizeof($list_array); $j++)
    {
        $list_array[$j] = "0".$list_array[$j];
    }

    for($k = 0; $k < sizeof($reverse_array); $k++)
    {
        $reverse_array[$k] = "1".$reverse_array[$k];
    }

    $list_array = array_merge($list_array,$reverse_array);
    $reverse_array = array_reverse($list_array);
}

for($l = sizeof($list_array) - $input; $l < sizeof($list_array); $l++)  
{
    print_r($list_array[$l]);
    echo "<br />";
}

?>

The second solution is given below

This solution will work till 63. After 63 this will show timeout error.

This will work till 63 when the 64 bit php running on 64 bit os. if it is 32 bit php running on 64 bit os, it will not work after 31.

<?php

    $n = 59;

    $intial = pow(2, $n) - $n;

    $length = pow(2, $n) - 1;

    for($i= $intial; $i <= $length; $i++)
    {
        $decimal = ($i >> 1) ^ $i;
        print_r(decbin($decimal));
        echo "<br />";
    }
?>

please help me for finding this solution.

question: how to solve above including $n = 64 and $n = 65

reference: https://www.geeksforgeeks.org/given-a-number-n-generate-bit-patterns-from-0-to-2n-1-so-that-successive-patterns-differ-by-one-bit/

Jees K Denny
  • 531
  • 5
  • 27
  • 2
    Where is a question? What problem are you solving? What do these "outputs" mean? – MBo Apr 06 '18 at 04:33
  • i think its explained in detail above, output for n-bits is the last n bits. – Jees K Denny Apr 06 '18 at 04:37
  • 1
    So you want to make output with 2^64 items? – MBo Apr 06 '18 at 05:11
  • Yes. @MBo for any better solution rather than making 2 ^ 64, please tell me. – Jees K Denny Apr 06 '18 at 05:14
  • But human life is too short for seeing all these numerous lines. You might want to restrict problem size with some reasonable value (for example n=6 to make human-observable amount to visually check code correctness, n~20-24 to check code speed) – MBo Apr 06 '18 at 05:33
  • The second solution i stated above is correctly worked till 63 without any error. i already checked manually till 5, its perfectly alright. after all i applied the program. i it is the problem of 64 bit os, i am looking for another solutin – Jees K Denny Apr 06 '18 at 05:37
  • But if your code generates 100 millions gray codes per second, you have to wait 3000 years to output all 2^64 codes (2^64/10^8/86400/365). – MBo Apr 06 '18 at 05:47
  • The Limit i alredy stated above. `1 <= $n <= 65` – Jees K Denny Apr 06 '18 at 05:48
  • 1
    @MBo I believe he only wants the last `$n` $n-bit gray codes, so for `$n = 65` there should be 65 lines of output even though there are `2^65` gray codes. – Paul Apr 06 '18 at 06:16
  • Yes. Exactly Said @Paulpro – Jees K Denny Apr 06 '18 at 06:17

2 Answers2

3

This should work for you:

<?php

print_r( getResult( 4 ) );

function getResult ( $n ) {
    $result = [];
    for ( $i = 0; $i < $n; $i++ ) {
        $result[] = arr_xor(
          str_split( str_pad( str_pad( strtr( decbin($n - $i - 1), '01', '10' ), (int)ceil(log($n - $i - 1, 2)), '0', STR_PAD_LEFT ), $n, '1', STR_PAD_LEFT ) ),
          str_split( '0' . str_pad( substr( str_pad( strtr( decbin($n - $i - 1), '01', '10' ), (int)ceil(log($n - $i - 1, 2)), '0', STR_PAD_LEFT ), -1-(int)ceil(log($n - $i - 1, 2)), -1), $n - 1, '1', STR_PAD_LEFT ) )
        );
    }
    return $result;
}

function arr_xor( $a, $b ) {
    $result = [];
    for ( $i = 0; $i < count( $a ); $i++ )
        $result[] = (int)$a[$i] ^ (int)$b[$i];
    return implode( '', $result );
}

It just uses the formula from your second solution (($i >> 1) ^ $i), but since you can't use that for integers greater than PHP_INT_MAX, it uses an array with each element representing one bit. It's not the most efficient solution, but can easily go beyond 65. $n = 1000 seems to be no problem.

Paul
  • 139,544
  • 27
  • 275
  • 264
  • could you please explain the process of 2 parameters inside the `getResult()` function ? – Jees K Denny Apr 06 '18 at 11:00
  • 1
    @JeesKDenny The first argument is an array containing the bits of `2**n-n+i` and the second is an array containing the bits of `(2**n-n+i) >> 1`. There are much simpler ways to generate those arrays for integers under MAX_INT_SIZE, but since I wanted it to work above `64` and `32`, I went with string operations. – Paul Apr 06 '18 at 15:02
  • @JeesKDenny You're probably better off just using something like http://php.net/manual/en/function.gmp-xor.php and will be able to go much further using that, than this answer with arrays does, but I didn't want to use that since it assumes you have the `gmp` extension already or are willing and able to compile and include it. – Paul Apr 06 '18 at 15:06
  • I already go through this library. but i am keen interest to do without using any library. thanks for the clarification. let me go through it. @Paulpro – Jees K Denny Apr 06 '18 at 15:09
0

Another answer and it is similar to @paulpro and it is the same idea i applied in the second solution. ($i >> 1) ^ $i

<?php

$n = 65;

for ( $i = 0; $i < $n; $i++ ) 
{
    $decimal = decbin($n - $i - 1);

    $replace = strtr( $decimal, '01', '10' );

    $cast = (int)ceil(log($n - $i - 1, 2));

    $padding = str_pad( $replace , $cast , '0', STR_PAD_LEFT );

    $a_string = str_pad( $padding, $n, '1', STR_PAD_LEFT );

    //shifting the bit to right
    $substring = substr( $a_string , 0 , -1);
    $b_string = str_pad( $substring , $n, '0', STR_PAD_LEFT );

    $a = str_split( $a_string );
    $b = str_split( $b_string );

    for ( $j = 0; $j < count( $a ); $j++ )
    {
        print_r((int)$a[$j] ^ (int)$b[$j]);
    }

    echo "\n";
}

?>
Jees K Denny
  • 531
  • 5
  • 27