Perl Weekly Challenge 371.

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

Task 1: Missing Letter

Submitted by: Reinier Maliepaard
You are given a sequence of 5 lowercase letters, with one
letter replaced by ‘?’. Each letter maps to its position in
the alphabet (‘a = 1’, ‘b = 2’, …, ‘z = 26’). The sequence
follows a repeating pattern of step sizes between
consecutive letters. The pattern is either a constant step
(e.g., ‘+2, +2, +2, +2’) or a simple alternating pattern of
two distinct steps (e.g., ‘+2, +3, +2, +3’).

Example 1
Input: @seq = qw(a c ? g i)
Output: e

The pattern of the sequence is +2,+2,+2,+2.
1: a
3: c
5: e
7: g
9: i

Example 2
Input: @seq = qw(a d ? j m)
Output: g

The pattern of the sequence is +3,+3,+3,+3.
1: a
4: d
7: g
10: j
13: m

Example 3
Input: @seq = qw(a e ? m q)
Output: i

The pattern of the sequence is +4,+4,+4,+4.
1: a
5: e
9: i
13: m
17: q

Example 4
Input: @seq = qw(a c f ? k)
Output: h

The pattern of the sequence is +2,+3,+2,+3.
1: a
3: c
6: f
8: h
11: k

Example 5
Input: @seq = qw(b e g ? l)
Output: j

The pattern of the sequence is +3,+2,+3,+2.
2: b
5: e
7: g
10: j
12: l


The simple pattern, with spacing m, is a particular case of the alternating pattern, with spacings m and n. Assuming the input is well formed, I need two consecutive values to get both n and m. For example, if the question mark is at position 0, I can use the intervals between positions 1 and 2, and between positions 2 and 3, i.e., the intervals starting at 1 and at 2, as they are unrelated to the unknown element at 0. Similarly, if the question mark is at position 2, I could use the intervals 3-4 and 0-1. Notice that 0 and 3 have opposite parity, so they information yielded by the two intervals is not redundant. I make a small table to illustrate this.

Position of ?  Interval 1  Interval 2 
0 1-2 2-3
1 2-3 3-4
2 3-4 0-1
3 0-1 1-2
4 1-2 2-3

Notice that in all cases, if the question mark is at position k, I can use the intervals starting at k+1 and k+2, both modulo 4. Finally, after finding both n and m I can reconstruct the character at position k from that at position k-1 or that at position k+1. This yields a 2-liner.

Examples:

perl -E '
for(@ARGV){/^(.*)\?.*$/;$k=length($1);@x=map{ord}split"";@s=map{$x[$_+1]-$x[$_]}
map{$_%4}($k+1,$k+2);say "$_ -> ", chr($k?$x[$k-1]+$s[0]:$x[$k+1]-$s[1]);}
' ac?gi ad?jm ae?mq acf?k beg?l

Results:

ac?gi -> e
ad?jm -> g
ae?mq -> i
acf?k -> h
beg?l -> j

For the full code I add a couple of tests.

 1  # Perl weekly challenge 371
 2  # Task 1:  Missing Letter
 3  #
 4  # See https://wlmb.github.io/2026/04/27/PWC371/#task-1-missing-letter
 5  use v5.36;
 6  use feature qw(try);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 S0 S1...
 9      to find the missing letter in string Sn.
10      The strings should contain four lower case English letters a-z and
11      exactly one question mark, and they should be compatible with
12      a simple or an alternating sequence.
13      FIN
14  my $length=5;
15  for(@ARGV){
16      try {
17          die "Wrong length: $_" unless length$_ == $length;
18          die "Only lowercase English letters or question marks allowed: $_" unless /^([a-z]|\?)*$/;
19          die "Expected only one question mark: $_" if /\?(.*)\?/;
20          die "Expected a question mark: $_" unless /^(.*)\?(.*)$/;
21          my $unknown = length($1);
22          my @codes = map{ord} split "";
23          my @separations = map{$codes[$_+1]-$codes[$_]}
24                            map {$_% ($length-1)}
25                            ($unknown+1, $unknown+2);
26          my @newcodes;
27          $newcodes[0] = $unknown?$codes[0]:$codes[1]-$separations[1];
28          @newcodes[$_]=$newcodes[$_-1] + $separations[($unknown+$_)%2] for 1..$length-1;
29          die "Replacement out of range: $_" unless ord("a") <= $newcodes[$unknown] <= ord("z");
30          my $newstring = join "", map {chr} @newcodes;
31          my $re=s/^(.*)\?(.*)$/$1.$2/r;
32          die "Inconsistent string: $_" unless $newstring=~/$re/;
33          say "$_ -> ", chr $newcodes[$unknown];
34      }
35      catch($e) { warn $e; }
36  }

Examples:

./ch-1.pl ac?gi ad?jm ae?mq acf?k beg?l

Results:

ac?gi -> e
ad?jm -> g
ae?mq -> i
acf?k -> h
beg?l -> j

Other examples:

./ch-1.pl 2>&1 abc a?c AB?DE a?c?e abcde ?abcd wxyz? ab?ef

Results:

Wrong length: abc at ./ch-1.pl line 18.
Wrong length: a?c at ./ch-1.pl line 18.
Only lowercase English letters or question marks allowed: AB?DE at ./ch-1.pl line 19.
Expected only one question mark: a?c?e at ./ch-1.pl line 20.
Expected a question mark: abcde at ./ch-1.pl line 21.
Replacement out of range: ?abcd at ./ch-1.pl line 30.
Replacement out of range: wxyz? at ./ch-1.pl line 30.
Inconsistent string: ab?ef at ./ch-1.pl line 33.

Task 2: Subset Equilibrium

Submitted by: Mohammad Sajid Anwar
You are given an array of numbers.

Write a script to find all proper subsets with more than one
element where the sum of elements equals the sum of their
indices.

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

Subset 1: (2, 1)
Values: 2 + 1 = 3
Positions: 1 + 2 = 3

Subset 2: (1, 4)
Values: 1 + 4 = 5
Positions: 2 + 3 = 5

Subset 3: (4, 3)
Values: 4 + 3 = 7
Positions: 3 + 4 = 7

Subset 4: (2, 3)
Values: 2 + 3 = 5
Positions: 1 + 4 = 5

Example 2
Input: @nums = (3, 0, 3, 0)
Output: (3, 0), (3, 0, 3)

Subset 1: (3, 0)
Values: 3 + 0 = 3
Positions: 1 + 2 = 3

Subset 2: (3, 0, 3)
Values: 3 + 0 + 3 = 6
Positions: 1 + 2 + 3 = 6

Example 3
Input: @nums = (5, 1, 1, 1)
Output: (5, 1, 1)

Subset 1: (5, 1, 1)
Values: 5 + 1 + 1 = 7
Positions: 1 + 2 + 4 = 7

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

Subset 1: (3, 2)
Values: 3 + 2 = 5
Positions: 1 + 4 = 5

Subset 2: (3, -1, 4)
Values: 3 + (-1) + 4 = 6
Positions: 1 + 2 + 3 = 6

Example 5
Input: @nums = (10, 20, 30, 40)
Output: ()

The examples show that the same numbers at different positions are to be considered as different set elements. There is a small notational error in example 5 above, as it seems to imply that the empty subset is the answer, while it is meant that the set of answers is empty. This could be fixed by using extra parenthesis in the answers of all the previous examples. I use subsets from Algorithm::Combinatorics to build all proper subsets and I filter them to keep those that are in equilibrium and have the appropriate length. I also use sum from List::Util to check the balance. The problem setup is based on one-based arrays, so in Perl I have to add the number of indices to the sum of indices. The result fits a two-liner.

Examples:

perl -MAlgorithm::Combinatorics=subsets -MList::Util=sum -E '
for(@ARGV){@d=split" ";@i=0..@d-1;@r=map{"[@d[@$_]]"}grep{1<@$_<@d
&&sum(@$_)+@$_==sum @d[@$_]}subsets(\@i);say"$_ -> [ @r ]";}
' -- "2 1 4 3" "3 0 3 0" "5 1 1 1" "3 -1 4 2" "10 20 30 40"

Results:

2 1 4 3 -> [ [4 3] [2 3] [1 4] [2 1] ]
3 0 3 0 -> [ [3 0 3] [3 0] ]
5 1 1 1 -> [ [5 1 1] ]
3 -1 4 2 -> [ [3 2] [3 -1 4] ]
10 20 30 40 -> [  ]

The full code is:

 1  # Perl weekly challenge 371
 2  # Task 2:  Subset Equilibrium
 3  #
 4  # See https://wlmb.github.io/2026/04/27/PWC371/#task-2-subset-equilibrium
 5  use v5.36;
 6  use feature qw(try);
 7  use Algorithm::Combinatorics qw(subsets);
 8  use List::Util qw(all sum);
 9  use Scalar::Util qw(looks_like_number);
10  die <<~"FIN" unless @ARGV;
11      Usage: $0 S0 S1...
12      to find the subsets of the space separated sets of numbers
13      Sn whose sum equal the sum of their indices (one-based).
14      FIN
15  for(@ARGV){
16      try {
17          my @numbers = split " ";
18          die "Expected space separated numbers: $_"
19              unless all {looks_like_number $_} @numbers;
20          my @indices = 0..@numbers-1;
21          my @results = map{
22              "[@numbers[@$_]]"
23          } grep {
24              1 < @$_ < @numbers                  #check length of subset
25              && sum(@$_)+@$_== sum @numbers[@$_] # check sums
26          }
27          subsets(\@indices);
28          say"$_ -> [ @results ]";
29      }
30      catch($e){ warn $e; }
31  }

Example:

./ch-2.pl "2 1 4 3" "3 0 3 0" "5 1 1 1" "3 -1 4 2" "10 20 30 40"

Results:

2 1 4 3 -> [ [4 3] [2 3] [1 4] [2 1] ]
3 0 3 0 -> [ [3 0 3] [3 0] ]
5 1 1 1 -> [ [5 1 1] ]
3 -1 4 2 -> [ [3 2] [3 -1 4] ]
10 20 30 40 -> [  ]

Notice that if large arrays are expected, then subsets can be used as an iterator, to generate and process the subsets one by one in a loop, instead of using grep and map.

/;

Written on April 27, 2026