Perl Weekly Challenge 224.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 224.

Task 1: Special Notes

Submitted by: Mohammad S Anwar
You are given two strings, $source and $target.

Write a script to find out if using the characters (only once) from source,
a target string can be created.

Example 1
Input: $source = "abc"
       $target = "xyz"
Output: false
Example 2
Input: $source = "scriptinglanguage"
       $target = "perl"
Output: true
Example 3
Input: $source = "aabbcc"
       $target = "abc"
Output: true

I can keep a hash with the characters of the source as keys and the value 1 if the character has not been seen in target, or less if it has already been seen. The special notes are those whose characters correspond to the (initial) value 1. This may be coded in a simple one liner.

Example 1:

perl -MList::Util=all -E '
print "@ARGV->"; $s{$_}=1 for split "", shift; say +(all {$s{$_}-->0} split "", shift)?"True":"False"
' abc xyz

Results:

abc xyz->False

Example 2:

perl -MList::Util=all -E '
print "@ARGV->"; $s{$_}=1 for split "", shift; say +(all {$s{$_}-->0} split "", shift)?"True":"False"
' scriptinglanguage perl

Results:

scriptinglanguage perl->True

Example 3:

perl -MList::Util=all -E '
print "@ARGV->"; $s{$_}=1 for split "", shift; say +(all {$s{$_}-->0} split "", shift)?"True":"False"
' aabbcc abc

Results:

aabbcc abc->True

The full code is similar

 1  # Perl weekly challenge 224
 2  # Task 1:  Special Notes
 3  #
 4  # See https://wlmb.github.io/2023/07/03/PWC224/#task-1-special-notes
 5  use v5.36;
 6  use List::Util qw(all);
 7  die <<~"FIN" unless @ARGV==2;
 8      Usage: $0 source target
 9      to find out if target may be written with non-repeated characters from source.
10      FIN
11  my ($source, $target)=@ARGV;
12  my %available;
13  $available{$_}=1 for split "", $source; # initialize available character counts
14  my $output=(all {$available{$_}-- > 0} split "", $target)?"True":"False";
15  say "source: $source, target: $target -> $output";

Examples:

./ch-1.pl abc xyz
./ch-1.pl scriptinglanguage perl
./ch-1.pl aabbcc abc

Results:

source: abc, target: xyz -> False
source: scriptinglanguage, target: perl -> True
source: aabbcc, target: abc -> True

Task 2: Additive Number

Submitted by: Mohammad S Anwar
You are given a string containing digits 0-9 only.

Write a script to find out if the given string is additive number. An additive number
is a string whose digits can form an additive sequence.

A valid additive sequence should contain at least 3 numbers. Except the first 2 numbers,
each subsequent number in the sequence must be the sum of the preceding two.


Example 1:
Input: $string = "112358"
Output: true

The additive sequence can be created using the given string digits: 1,1,2,3,5,8
1 + 1 => 2
1 + 2 => 3
2 + 3 => 5
3 + 5 => 8

Example 2:
Input: $string = "12345"
Output: false

No additive sequence can be created using the given string digits.
Example 3:
Input: $string = "199100199"
Output: true

The additive sequence can be created using the given string digits: 1,99,100,199
 1 +  99 => 100
99 + 100 => 199

I can test a given choice for the first two numbers and generate the remaining numbers in the sequence until I have success (I get to the end of the string) or failure (I generate a number that doesn’t follow in the sequence), in which case, I can test the next pair of generating numbers. I go on until I succeed and the result is true or until I consume all generating number pairs. I’ll leave some optimization to the full code. The solution may be coded into a three-liner.

Examples:

perl -E '
L: for(@ARGV){$l=length; for my $x(1..$l){$c=$_; $f=substr $c,0,$x,""; for my $y(1..$l){
$d=$c; $g=substr $d,0,$y,""; $h=$f+$g; while($d=~s/^$h//){say("$_ -> True"), next L if
length $d==0; ($g, $h)=($h, $g+$h)}}} say "$_ -> False";}
' 112358 12345 199100199

Results:

112358 -> True
12345 -> False
199100199 -> True

Other examples:

perl -E '
L: for(@ARGV){$l=length; for my $x(1..$l){$c=$_; $f=substr $c,0,$x,""; for my $y(1..$l){
$d=$c; $g=substr $d,0,$y,""; $h=$f+$g; while($d=~s/^$h//){say("$_ -> True"), next L if
length $d==0; ($g, $h)=($h, $g+$h)}}} say "$_ -> False";}
' 1001002003005008001300 101102203305 991100101201

Results:

1001002003005008001300 -> True
101102203305 -> True

 1  # Perl weekly challenge 224
 2  # Task 2:  Additive Number
 3  #
 4  # See https://wlmb.github.io/2023/07/03/PWC224/#task-2-additive-number
 5  use v5.36;
 6  use List::Util qw(max min);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 S1 [S2...]
 9      to check if the strings S1 S2... correspond to additive numbers.
10      FIN
11   INPUT: for(@ARGV){
12       say("String should contain digits only: $_"), next INPUT unless /^\d+$/;
13       my $length=length;
14       FIRST: for my $length1(1..$length/2){ # no need to consider larger first numbers
15  	 my $copy=$_; # make a copy of input string
16  	 my $previous=substr $copy, 0, $length1, ""; # choose the starting number
17  	 for my $length2(1..$length/2){
18  	     # ignore numbers that are too large:
19  	     next FIRST if 2*max($length1,$length2) > $length - min($length1, $length2);
20  	     my $copy_of_copy=$copy;
21  	     my $current=substr $copy_of_copy, 0, $length2, "";
22  	     my $next=$previous + $current;
23  	     while($copy_of_copy=~s/^$next//){ # found next number in sequence?
24  		 say("$_ -> True"), next INPUT if length $copy_of_copy==0; # Finished?
25  		 ($current, $next)=($next, $current+$next)
26  	     }
27  	 }
28       }
29       say "$_ -> False";
30  }
31

Examples:

./ch-2.pl 112358 12345 199100199 1001002003005008001300 101102203305 991100101201

Results:

112358 -> True
12345 -> False
199100199 -> True
1001002003005008001300 -> True
101102203305 -> True
991100101201 -> True

/;

Written on July 3, 2023