Perl Weekly Challenge: Week 295

Challenge 1:

Word Break

You are given a string, $str, and list of words, @words.

Write a script to return true or false whether the given string can be segmented into a space separated sequence of one or more words from the given list.

Example 1
Input: $str = 'weeklychallenge', @words = ("challenge", "weekly")
Output: true
Example 2
Input: $str = "perlrakuperl", @words = ("raku", "perl")
Output: true
Example 3
Input: $str = "sonsanddaughters", @words = ("sons", "sand", "daughters")
Output: false

I am still wondering if there is a cleverer way to solve this challenge but the one I came up with is pretty compact.

I assume the input will be in command-line parameters. The first will be $str and the rest will be @words. The way to express this in Raku is like this:

MAIN($str, *@words)

But the problem is function parametes in Raku are immutable and, as we shall see, we will need to modify $str.

So my MAIN()signature just looks like this:

MAIN(*@words)

and the first line of that function is this:

my $str = @words.shift;

Now $str is mutable.

Then for each word in @words...

for @words -> $word {

...I just globally (the :g flag) delete it from $str.

    $str ~~ s:g/$word//;
}

If after all words have been removed, the length of $str is less than 1 (or I could have said equals 0; don't remember why I didn't.) we print True otherwise we print False.

say $str.chars < 1;

(Full code on Github.)

The Perl version works the same way but we don't need to worry about immutability.

my $str = shift;
my @words = @ARGV;

for my $word (@words) {
    $str =~ s/$word//g;
}

Also because Perl didn't have a formal Boolean type until recently and even the experimental feature in the latest versions doesn't include printable representations of the truth values (yet?), we have to explicitly print true or false.

say length $str < 1 ? 'true' : 'false';

(Full code on Github.)

Challenge 2:

Jump Game

You are given an array of integers, @ints.

Write a script to find the minimum number of jumps to reach the last element. $ints[$i] represents the maximum length of a forward jump from the index $i. In case last element is unreachable then return -1.

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

Jump 1 step from index 0 then 3 steps from index 1 to the last element.
Example 2
Input: @ints = (2, 3, 0, 4)
Output: 2
Example 3
Input: @ints = (2, 0, 0, 4)
Output: -1

Once again we will assume that the input is being provided via command-line parameters.

We need to keep track of how far we can jump. This will initially be the first value in @ints. In hindsight I should have given this a clearer name I think.

my $maxJumps = @ints[0];

We also need to know how many steps we can take with this jump before we need another one. This will also initially be the first value in @ints.

my $step = @ints[0];

How many jumps we have actually taken.

my $jumps = 1;

Now for each index of @inta except the first (because we are already using that one) and the last (because that is the goal)...

for 1 ..^ @ints.end -> $i {

If the current index plus the jump length from this index is greater than the current $maxJumps we update the value of $maxJumps.

    if $i + @ints[$i] > $maxJumps {
        $maxJumps = $i + @ints[$i];
    }

We decrement the value of $step.

    $step--;

If $step is still greater than 0, we make another round of the loop.

If it is 0, we need a another jump.

    if $step == 0 {
        $jumps++;

If the current index is greater than the current value of $maxJumps you can't move forward so we admit defeat, set the number of jumps to -1 and stop processing.

        if $i >= $maxJumps {
            $jumps = -1;
            last;
        }

Otherwise we reset $steps for the new jump;

        $step = $maxJumps - $i;
    }
}

Finally we can print how many jumps it took to reach the goal or -1 if we couldn't make it.

say $jumps;

(Full code on Github.)

And this is the Perl version.

my $maxJumps = $ints[0];
my $step = $ints[0];
my $jumps = 1;

for my $i (1 .. scalar @ints - 2) {
    if ($i + $ints[$i] > $maxJumps) {
        $maxJumps = $i + $ints[$i];
    }
    $step--;

    if ($step == 0) {
        $jumps++;
        if ($i >= $maxJumps) {
            $jumps = -1;
            last;
        }
        $step = $maxJumps - $i;
    }
}
say $jumps;

(Full code on Github.)