Factoring Hackerrank Solution - Using Only Algorithms

1

I'm learning to program and I'm doing the hackerrank algorithm exercises. I'm in the migratory birds exercise.

Accessing the exercise requires login access. As many do not have access, I copy and paste the exercise here:

  

You have been asked to help study the population of birds migrating   across the continent. Each type of bird you are interested in will be   identified by an integer value. Each time a particular kind of bird is   spotted, its id number will be added to your array of sightings. You   would like to be able to find out which type of bird is most common   given a list of sightings.If two or more types of birds are equally   common, choose the type with the smallest ID number.

     

Function Description

     

Complete the migratoryBirds function in the editor below. It has two   parameters:

     

Integer, denoting the number of elements in the input array. Integer   Array, with array elements denoting the respective type numbers of   each bird in the flock. The function must return an integer denoting   the type number of the most common bird.

     

Raw Input Format

     

The first line contains an integer denoting n, the number of birds   sighted and reported in the array. The second line describes air as n   space-separated integers representing the type numbers of each bird   sighted.

Personal,

My solution is this:

function migratoryBirds($n, $ar) { 
    $ret = [];

    for ( $i = 0 ; $i < $n ; $i++ ){        
        $frequencia = 0;
        for ( $k = 0 ; $k < $n ; $k++) { 
            if( $ar[ $i ] == $ar[ $k ] ) {
                $ret[ $ar[ $i ] ] = 1 + $frequencia;
                $frequencia++;
            }   
        }
    }
    $arrayMaiorFrequencia = $ret[ $ar[0] ];
    $menorChaveArrayMaiorFrequencia = $ar[0];

    for ( $i = 0; $i < $n; $i++ ) {
        if( $ret[ $ar[$i] ] == $arrayMaiorFrequencia && $ar[$i] < $menorChaveArrayMaiorFrequencia ) {
            $menorChaveArrayMaiorFrequencia = $ar[$i];
        } elseif($ret[ $ar[$i] ] > $arrayMaiorFrequencia) {
            $arrayMaiorFrequencia = $ret[ $ar[$i] ];    
            $menorChaveArrayMaiorFrequencia = $ar[$i];
        }
    }

    return $menorChaveArrayMaiorFrequencia;
}

Function inputs are defined by the exercise, that is, $ ar is an array of int and $ n is the number of array elements.

However, I wonder if you can factor this solution? Note: Although you are using php, and some functions in php would make the solution much easier and faster, I CAN NOT USE ANY FUNCTION OF PHP , just the concept of algorithms. So how do I make my solution cleaner?

    
asked by anonymous 18.04.2018 / 04:11

2 answers

0

I start by saying that you do not need to have 2 for to calculate the frequencies:

$ret = [];

for ( $i = 0 ; $i < $n ; $i++ ){        
    $frequencia = 0;
    for ( $k = 0 ; $k < $n ; $k++) { 

You may as well just do it with a for incrementing in the position that matters, working as well as a map. As for finding the least, both its if and else if should have equal paths facilitating the algorithm. As a small aside for normal arrays, if you do not need to use indices specifically, it becomes simpler to use foreach , as it avoids having to crawl constantly.

Given these points I mentioned, and assuming the nomenclature of the variables in Portuguese, to coincide with what you have, you could do this:

function migratoryBirds($n, $ar) { 
    $passaros = [];
    foreach ($ar as $passaro){
        $passaros[$passaro] = ($passaros[$passaro] ?? 0) + 1;
    }

    $maiorContagem = 0;
    $menorId = $ar[0];
    foreach ($passaros as $id => $contagem) {
        if ($contagem > $maiorContagem || ($contagem == $maiorContagem && $id < $menorId)){
            $maiorContagem = $contagem;
            $menorId = $id;
        }
    }

    return $menorId;
}

See the code working on Ideone

Notice that in this my solution I have added both cases of greater counting checking or equal counting and smaller id:

if ($contagem > $maiorContagem || ($contagem == $maiorContagem && $id < $menorId)){

Making this part simpler.

I made the initial frequency count with just a for and used the null coalescing operator to get the value that the count for that bird already had or zero if it did not exist:

($passaros[$passaro] ?? 0)

Of course you could do this in other ways, for example at the expense of isset , if you wanted to support older versions of php.

Edit :

Of course, it only works with for and not foreach , I only opted for foreach because it is simpler and idiomatic. Changing my solution to make use of only for to find the frequencies would look like this:

$passaros = [];
for ($i = 0; $i < $n; $i++){
    $passaros[$ar[$i]] = ($passaros[$ar[$i]] ?? 0) + 1;
}

According to my solution it is not possible to use a simple%% of the check in the greater, which is the next loop / cycle, because only a few positions are defined.

In your input example of for the count array looks like this:

array(2) {
  [5]=>
  int(3)
  [3]=>
  int(3)
}

Here you see that only the position [5,5,5,3,3,3] and 3 are assigned, which means that I can not go through positions 0,1,2, etc ... up to the size that would be 5 . >

You can also do this first 2 without null coalescing operator and using for :

$passaros = [];
for ($i = 0; $i < $n; $i++){
    //se a contagem para este pássaro ainda não existe define como 0
    if(!isset($passaros[$a[$i]]){
        $passaros[$ar[$i]] = 0;
    }

    $passaros[$ar[$i]]++;
}
    
18.04.2018 / 13:26
0

@Isac,

I was able to reach the following solution using 1 for and 1 if only

function migratoryBirds($n, $ar) { 
    $contagem = 0;
    $passaro = [];
    $maior = 0;
    $menorChave= 0 ;
    for($i=0; $i < $n; $i++ ){
        $passaro[$ar[$i]] = ( $passaro[ $ar[$i] ] ?? 0 ) + 1;
        if($passaro[$ar[$i]] > $maior || $passaro[$ar[$i]] == $maior && $ar[$i] < $menorChave ) {
            $maior = $passaro[$ar[$i]];
            $menorChave = $ar[$i];  
        }
    }   
    return $menorChave;
}
    
19.04.2018 / 04:35