TWC 194: Bag Time!

In which analysis speeds, and mis-leads.

(Still editing!)

Old Mr. Kringle is soon gonna jingle
The bells that'll tingle all your troubles away
Everybody's waitin' for the man with the bag
'cause Christmas is coming again -- The Brian Setzer Orchestra

TWC Task #1 - Digital Clock

Task

Given time in the format hh:mm with one missing digit, find the highest digit 0-9 that makes it a valid time.

Observations

Example #4 says '2?:00' should return 3, which tells us that we should work with 24-hour time, and that 24:00 is not allowed as a alternate expression of 00:00 the-next-day.

  • Question mark in 4th digit place, the answer is 9.
  • Question mark in 3th digit place, the answer is 5.
  • Question mark in 2th digit place, the answer is 9 or 3, depending on whether the 1st digit is 0|1 or 2.
  • Question mark in 1st digit place, the answer is 2 or 1, depending on whether the 2nd digit is 0..3 or 4..9.

There are only 2460=1440 possible times, but only (1060)+( 360)+(2410)+(24* 6) = 1164 possible (valid) inputs.

Raku

sub is_time_valid ( Str $s --> Bool ) {
    constant $valid_times = ( ^24 X ^60 ).map( *.fmt('%02d', ':') ).Set;
    return $s ∈ $valid_times;
}
sub task1 ( Str $s --> UInt ) {
    return (9…0).first: { $s.subst( '?', $_ ).&is_time_valid };
}

Perl


TWC Task #2 - Frequency Equalizer

Task

Given a string, determine whether removing only one character can make the frequency of the remaining characters the same.

Observations

The test cases led many participants to shortcut the analysis and produce concise solutions that would fail one of these cases:

  • 'aaaaab', 1

The count of a (5) is not within striking distance of the count of b (1), but because b is the only solo character, removing it would succeed.

  • 'aaabbbcc', 0

3 can be reduced to 2 be removing 1, but there are two letters that each have 3, so the frequency cannot be made equal with just one character removed.

Alternately, one of the groups has only one letter in it (c), and abs(3-2) == 1, but in the wrong direction; you would have to add a c to equalize.

  • 'abcd', 1

Removing any of the letters leaves us with equal frequency.

Generating test cases

Of interest to me were methods to generate minimal sets of test cases:

raku -e 'my @a = "a".."e"; for ( [X] (@a xx 5) ) { say .join if [le] .list and (.join ~~ /^a+[b+[c+[d+[e+]?]?]?]?$/)}' | m
aaaaa aaaab aaabb aaabc aabbb aabbc aabcc aabcd abbbb abbbc abbcc abbcd abccc abccd abcdd abcde

Longer code, but more efficient to run:

raku -e 'my $w = 5; my $f = "\%0{$w}b"; for ^(2 ** $w) { my @bin = .fmt($f).comb;
my $c = "a";
my $out = "a";
for @bin {
    $c++ if +$_;
    $out ~= $c;
}
say $out;
}'

The above is not fully minimal; it misses the nuance that aabbc and aabcc both are "two of two, and one of one". We need partitioning!

perl -MList::Util=zip -MInteger::Partition -wE 'my $i = Integer::Partition->new(shift); while (my $p = $i->next){say map { $_->[0] x $_->[1] } zip [("a".."z")[keys @$p]], $p}' 5
aaaaa
aaaab
aaabb
aaabc
aabbc
aabcd
abcde

Raku

# Best compromise between performance, complexity, reducing chance to "get it wrong",
# and likelihood of a maintenance programmer to reverse-engineer the original requirements.
sub task2 ( Str $s --> Bool ) {
    my BagHash $b = $s.comb.BagHash;
    my @k = $b.keys;

    for @k -> $k {
        $b.remove: $k;
        return True if $b.values.unique.elems == 0|1;
        $b.add:    $k;
    }
    return False;
}

Perl

Translation of my Raku solution, with %h as a improvised Bag. The code grep { $_ != 0 } is needed to adapt to the hash entry not disappearing when the value goes to 0.

use v5.36;
use List::Util qw<uniq>;
sub task2 ($s) {
    my %h;
    $h{$_}++ for split '', $s;
    my @k = keys %h;

    for my $k (@k) {
        $h{$k}--;

        my $c = 0 + grep { $_ != 0 } uniq values %h;

        return 1 if $c == 0
                 or $c == 1;

        $h{$k}++;
    }
    return 0;
}

He'll make this December the one you'll remember
The best and the merriest you ever did have
Everybody's waitin', they're all congregating
Waitin' for the man with the bag -- #Voctave {A Cappella, and Breath-taking; We got to see them in concert last week!}

Leave a comment

About Bruce Gray

user-pic "Util" on IRC and PerlMonks. Frequent speaker on Perl and Raku, but infrequent blogger.