Welcome To Weekly Challenge #303! Because it’s been over a year, I forgot about the HTTP status codes, and the opportunities for blog names based on them.

https://http.cat/images/303

See also:

303 is also a compound number (101 * 3) and the Area Code for Denver, Colorado, and the surrounding area. Interestingly, 301 is the area code for western Maryland, including the areas around the District of Columbia. If you were to go back to Rockville and waste another year, you’d be 301-ing to 301.

Due to a time crunch, I didn’t do these in Python. Maybe next time.

Task 1: 3-digits Even

Submitted by: Mohammad Sajid Anwar
You are given a list (3 or more) of positive integers, @ints.

Write a script to return all even 3-digits integers that can be formed using the integers in the given list.

Let’s Talk About It

This is another problem where Algorithm::Permute becomes useful, but you have to watch the output, because [3, 3, 3] gives you three permutations: [3, 3, 3], [3, 3, 3] and [3, 3, 3].

Perl makes conversion from string to integer easy, and I use 0 + $string to turn numbers like 011 to 11. I avoid duplications with next and a hashref, and determine evenness with modulus.

Show Me The Code!

#!/usr/bin/env perl

use strict;
use warnings;
use experimental qw{ say state postderef signatures };

use Algorithm::Permute;

my @examples = (

    [ 2, 1, 3, 0 ],
    [ 2, 2, 8, 8, 2 ],
);

for my $example (@examples) {
    my @output = even_3_digits( $example->@* );
    my $output = join ', ', @output;
    my $input  = join ', ', $example->@*;
    say <<"END";
    Input:  \@ints = ($input)
    Output: ($output)
END
}

sub even_3_digits(@array) {
    my @output;
    my $done;
    my $p = Algorithm::Permute->new( \@array, 3 );
    while ( my @p = $p->next() ) {
        my $int = 0 + ( join '', @p );
        next if $int < 100;
        next if $int % 2 != 0;
        next if $done->{$int}++;
        push @output, $int;
    }
    @output = sort @output;
    return @output;
}

$ ./ch-1.pl
    Input:  @ints = (2, 1, 3, 0)
    Output: (102, 120, 130, 132, 210, 230, 302, 310, 312, 320)

    Input:  @ints = (2, 2, 8, 8, 2)
    Output: (222, 228, 282, 288, 822, 828, 882)

Task 2: Delete and Earn

Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints.

Write a script to return the maximum number of points you can earn by applying the following operation some number of times.

Pick any ints[i] and delete it to earn ints[i] points.
Afterwards, you must delete every element equal to ints[i] - 1 and every element equal to ints[i] + 1.

Let’s Talk About It

Ahem.

THIS looks like a job for … RECURSION!

For my solution, I choose one of the unique values of the array. For the example of [2, 2, 3, 3, 3, 4], I go with [2, 3, 4] because any one of the 3s will give the same result.

The work of removing all the 2s and 4s from the array, and the first 3 in the array takes place first, as well adding the chosen 3 to the point tally, occurs before testing for end conditions, and then we go with the unique remaining values and go again.

I go to List::Util again. first { $array[$_] == $n } 0 .. -1 + scalar @array gives us the index of the value we need to remove from the array. uniq sort @array gives us every individual value without repeats. max @output removes everything but the maximum number of points at each recursion, which is what we seek.

Show Me The Code!

#!/usr/bin/env perl

use strict;
use warnings;
use experimental qw{ say state postderef signatures };

use List::Util qw{ first max uniq };
use Carp;

my @examples = (

    [ 3, 4, 2 ],
    [ 2, 2, 3, 3, 3, 4 ],
    [qw{ 1 1 1 2 2 2 3 3 3 4 4 4 5 5 }],
);

for my $example (@examples) {
    my $ints   = join ', ', $example->@*;
    my $output = delete_and_earn( $example->@* );
    say <<"END";
    Input:  \@ints = ($ints)
    Output: $output
END
}

sub delete_and_earn (@array) {
    my @output;
    for my $i ( uniq sort @array ) {
        push @output, _delete_and_earn( $i, 0, @array );
    }
    return max @output;
}

sub _delete_and_earn ( $n, $v, @array ) {
    my @output;
    $v += $n;
    @array = grep { $_ != $n - 1 } @array;
    @array = grep { $_ != $n + 1 } @array;
    my $i = first { $array[$_] == $n } 0 .. -1 + scalar @array;
    $array[$i] = undef;
    @array = grep { defined } @array;
    if ( !scalar @array ) {
        return $v;
    }
    for my $nn ( uniq sort @array ) {
        push @output, _delete_and_earn( $nn, $v, @array );
    }
    return max @output;
}
$ ./ch-2.pl
    Input:  @ints = (3, 4, 2)
    Output: 6

    Input:  @ints = (2, 2, 3, 3, 3, 4)
    Output: 9

    Input:  @ints = (1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5)
    Output: 22

If you have any questions or comments, I would be glad to hear it. Ask me on Mastodon or make an issue on my blog repo.