site.base_url }}/">The Bear's Den -->

The Bear's Den

Enter at your own risk

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:

These partitions need to be sorted by different criteria and then be concatenated.

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.