30 August 2024 | Challenge 284 |
Relatively Lucky
Task 1: Lucky Integer
Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints
.
Write a script to find the lucky integer if found otherwise return -1
.
If there are more than one then return the largest.
A lucky integer is an integer that has a frequency in the array equal to its value.
Example 1
Input: @ints = (2, 2, 3, 4)
Output: 2
Example 2
Input: @ints = (1, 2, 2, 3, 3, 3)
Output: 3
Example 3
Input: @ints = (1, 1, 1, 3)
Output: -1
Solution
The task may be almost literally transformed into the language of PDL
:
We find the frequencies for @ints
, sorted in ascending order by value, limit these to lucky numbers where the value equals the frequency and pick the largest (i.e. the final) value - or minus one.
use strict;
use warnings;
use PDL '2.017';
use PDL::NiceSlice;
sub lucky_integer {
my ($freq, $val) = rle long(@_)->qsort;
my $lucky = $val->where($freq == $val);
$lucky->isempty ? -1 : $lucky(-1;-);
}
See the full solution to task 1.
Task 2: Relative Sort
Submitted by: Mohammad Sajid Anwar
You are given two list of integers, @list1
and @list2
.
The elements in the @list2
are distinct and also in the @list1
.
Write a script to sort the elements in the @list1
such that the relative order of items in @list1
is same as in the @list2
.
Elements that is missing in @list2
should be placed at the end of @list1
in ascending order.
Example 1
Input: @list1 = (2, 3, 9, 3, 1, 4, 6, 7, 2, 8, 5)
@list2 = (2, 1, 4, 3, 5, 6)
Output: (2, 2, 1, 4, 3, 3, 5, 6, 7, 8, 9)
Example 2
Input: @list1 = (3, 3, 4, 6, 2, 4, 2, 1, 3)
@list2 = (1, 3, 2)
Output: (1, 3, 3, 3, 2, 2, 4, 4, 6)
Example 3
Input: @list1 = (3, 0, 5, 0, 2, 1, 4, 1, 1)
@list2 = (1, 0, 3, 2)
Output: (1, 1, 1, 0, 0, 3, 2, 4, 5)
Solution
We may build two partitions from @list1
:
- partition 1 contains all elements that appear in
@list2
- partition 2 contains the rest.
These partitions need to be sorted by different criteria and then be concatenated.
- For partition 1 we perform a simplified counting sort with an order as given by
@list2
. - For partition 2 we perform a standard numerical sort.
As we need one pass through the list to build the two partitions anyway, we may perform the counting step for the counting sort along the way.
Afterwards we find the sorted partition 1 by collecting the counted number of items in the order given by @list2
and we numerically sort partition 2.
use strict;
use warnings;
use experimental 'signatures';
sub relative_sort ($list1, $list2) {
(\my %list2)->@{@$list2} = ();
my @part2;
for my $n (@$list1) {
if (exists $list2{$n}) {
$list2{$n}++;
} else {
push @part2, $n;
}
}
[
(map +($_) x $list2{$_}, @$list2),
(sort {$a <=> $b} @part2),
];
}
See the full solution to task 2.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.