Perl Weekly Challenge: Week 80
Challenge 1:
Smallest Positive Number
You are given unsorted list of integers
@N
.Write a script to find out the smallest positive number missing.
Example 1:
Input: @N = (5, 2, -2, 0)
Output: 1
Example 2:
Input: @N = (1, 8, -1)
Output: 2
Example 3:
Input: @N = (2, 0, -1)
Output: 1
I'll start with my Raku solution.
sub MAIN(
*@N #= a list of integers
) {
Because we are only interested in positive integers, we can safely get rid of any negative
elements from @N
. We sort the resulting list, @positives
, so that the positive integers are in numeric order.
my @positives = @N.grep({ $_ >= 0}).sort;
This means that the first element of @positives
is the current smallest positive number.
my $smallest = @positives[0];
Now we go through the rest of the elements in @positives
.
for 1 .. @positives.elems -> $i {
If the difference between $smallest
and the current element is greater than 1, we know
we have a missing number. We can add 1 to $smallest
and stop because this is the answer.
I added // Inf
in there to deal with the edge case of the last element in the list.
if (@positives[$i] // Inf) - $smallest > 1 {
$smallest++;
last;
If it isn't, we just make the current element the new smallest number.
} else {
$smallest = @positives[$i];
}
}
And once the array has been fully traversed, we can just print $smallest
and there's the answer.
say $smallest;
}
This is the Perl version of the code above.
my @N = @ARGV;
my @positives = sort grep { $_ >= 0; } @N;
my $smallest = $positives[0];
for my $i (1 .. scalar @positives) {
if (($positives[$i] // 'inf') - $smallest > 1) {
$smallest++;
last;
} else {
$smallest = $positives[$i];
}
}
say $smallest;
Challenge 2:
Count Candies
You are given rankings of
@N
candidates.Write a script to find out the total candies needed for all candidates. You are asked to follow the rules below:
a) You must given at least one candy to each candidate.
b) Candidate with higher ranking get more candies than their mmediate neighbors on either side.
Example 1:
Input: @N = (1, 2, 2)
Explanation:
Applying rule #a, each candidate will get one candy. So total candies needed so far 3. Now applying rule #b, the first candidate do not get any more candy as its rank is lower than it's neighbours. The second candidate gets one more candy as it's ranking is higher than it's neighbour. Finally the third candidate do not get any extra candy as it's ranking is not higher than neighbour. Therefore total candies required is 4.
Output: 4
Example 2:
Input: @N = (1, 4, 3, 2)
Explanation:
Applying rule #a, each candidate will get one candy. So total candies needed so far 4. Now applying rule #b, the first candidate do not get any more candy as its rank is lower than it's neighbours. The second candidate gets two more candies as it's ranking is higher than it's both neighbour. The third candidate gets one more candy as it's ranking is higher than it's neighbour. Finally the fourth candidate do not get any extra candy as it's ranking is not higher than neighbour. Therefore total candies required is 7.
Output: 7
In Raku:
sub MAIN(
*@N #= a list of integers
) {
I start by giving every candidate (i.e. every element in the array @N
one candy as per rule #a. This can be done
very concisely thanks to the xx
operator.
my @candies = 1 xx @N.elems;
Then for each element in @N
, I look at the neighbors on either side. If the current element is greater than the one on the
left, it gets one more candy and ditto if it is greater than the one to its right. Once again I have to check if the element is
defined with //
to deal with the edge cases of the first and last elements.
for 0 ..^ @N.elems -> $i {
if @N[$i] > (@N[$i - 1] // Inf) {
@candies[$i]++;
}
if @N[$i] > (@N[$i + 1] // Inf) {
@candies[$i]++;
}
}
Finally, all that remains is to total up how many candies were given altogether (easy with [+]
) and print that total.
say [+] @candies;
}
Perl lacks certain amenities that Raku provides.
my @N = @ARGV;
Instead of xx
I used map()
;
my @candies = map{ 1; } @N;
for my $i (0 .. scalar @N - 1) {
if ($N[$i] > ($N[$i - 1] // 'inf')) {
$candies[$i]++;
}
if ($N[$i] > ($N[$i + 1] // 'inf')) {
$candies[$i]++;
}
}
I could have used map()
again here instead of [+]
but I chose to use a foreach
loop instead.
my $total = 0;
foreach (@candies) {
$total += $_;
}
say $total;