The Weekly Challenge - 262 (March 25th 2024)
Task #1: Max Positive Negative
You are given an array of integers, @ints. Write a script to return the maximum number of either positive or negative integers in the given array.
Assumption there are no zero values (or we count them as neither +ve or -ve
Example 1
Input: -3,1,2,-1,3,-2,4 Output: 4
4 positive and 3 negative values – so answer is 4.
Example 2
Input: -1,-2,-3,1 Output: 3
3 negative values, 1 positive – answer 3
Example 3
Input: 1,2 Output: 2
Only 2 positive values – answer 2
Solution
We use the spaceship operator <=>
to get the signum of each value – and the perl trick that in an array of 3 elements the -1 element is the 2 element.
We then use the spaceship operator again to get the maximum of the +/- counts – which are 1 & 2.
ADDENDUM
If you want to count 0s
as both +ve and -ve then the last line can be replaced with “$c[ $c[1] <=> $c[2] ] + $c[0]
“.
262-task1.pl - perl
sub max_positive_negative {
my @c = (0, 0, 0);
$c[ $_ <=> 0 ] ++ for @_;
$c[ $c[1] <=> $c[2] ]
}
Task #2: Count equal divisible
You are given an array of integers, @ints
and an integer $k
. Write a script to return the number of pairs ($i, $j)
where $i < $j
, $ints[$i] == $ints[$j]
and $i*$j
is divisible by $k
;
Here we are going to produce two solutions, in both cases $k
is passed in as the last element of the array (hence pop
rather than shift
):
Example 1
Input: @ints = (3,1,2,2,2,1,3), $k = 2 Output: 4
The two 3s are in positions 0 & 6 product even so + 1
The two 1s are in positions 1 & 5 the product is not even so + 0
The three 2s are in positions 2,3,4 all products are even so + 3
Example 2
Input: @ints = (1,2,3), $k = 1 Output: 0
None are equal
Example 3
Input: @ints = (2,1,1,1,1,3,3,3,3), $k = 12 Output: 2
Only index pairs to consider are 2,6; 3,4; 3,8; 4,6
Example 4
Input: @ints = (5,3,1,3,4,1,1,3,5,2,4,2,4,1,1,2,2,3,3,2), $k = 6 Output: 13
Example 5
Input: @ints = (6,6,1,9,1,3,6,2,5,1,4,8,9,6,9,9,4,2,2,4,9, 6,2,4,8,4,1,6,9,4,4,6,4,7,3,4,4,4,1,4,6,6, 1,1,5,6,9,5,8,7,2,6,6,3,8,4,8,4,6,8,5,2,4, 8,5,5,3,3,6,7,4,8,6,5,5,7,3,9,4,4,4,4,7,2, 6,8,7,7,3,3,5,3,2,5,5,6,1,5,1,1), $k = 12 Output: 171
Solution 1 - nested loop over all pairs (naive)
We loop through $i
& $j
– we check that the product is divisible by $k
(it is divisible if ($i*$j) % $k
is 0
), then values are the same and if they increment the count $c
– we use ||
and &&
to replace if not true and if true; Note as we are using a postfix for
then “$j
” is replaced by “$_
“
perl
sub count_equal_divisible {
my($k,$c) = (pop,0);
for my $i ( 0 .. $#_ - 1 ) {
( $i * $_ ) % $k || $_[ $i ] == $_[ $_ ]
&& $c++ for $i + 1 .. $#_;
}
$c
}
Solution 2 - hashing and then looping over common values
In this case we create a hash for which the keys are the values in the list and the values are arrays of the indices of that number.
We then do the solution 1 loop for each element of the hash, i.e. the indices which have the same values – this though is simplified as we no longer need to do the value comparison inside the loops.
perl
sub count_equal_divisible_h {
my ( $k, $p, $c, %h ) = ( pop, 0, 0 );
push @{ $h{$_} }, $p++ for @_;
for my $x ( values %h ) {
while( @{$x} ) {
my $i = shift @{$x};
( $i * $_ ) % $k || $c++ for @{$x};
}
}
$c
}
~
Performance
For the examples in the challenge the speed for the naïve version is only roughly 2% faster than the hash method, so the hashing overhead is not great;
But an example with a list of 20 numbers between 1 & 5 the hash method is about 110% faster;
An example with a list of 100 numbers between 1 & 9 the hash method is about 420% faster;
About The Weekly Challenge
The weekly challenge was set up Mohammad Anwar approximately 5 years ago - each Monday two problems are set for the "team" to solve.
These are posted at: