Last word, buddy
Weekly challenge 331 — 21 July 2025
Week 331: 21 Jul 2025
You are given two strings, $source
and $target
.
Write a script to find out if the given strings are Buddy Strings.
If swapping of two letters in one string makes it the same as
the other then they are Buddy Strings.
Example 1 Input: $source = 'duck' $target = 'dcuk' Output: true The swapping of 'u' with 'c' makes them buddy strings. Example 2 Input: $source = 'love' $target = 'love' Output: false Example 3 Input: $source = 'fodo' $target = 'food' Output: true Example 4 Input: $source = 'feed' $target = 'feed' Output: true
There are a number of ways to approach this challenge, but I looked for one that made just a single pass along the strings - ie no nested loops.
My conclusion was that it was best to separate out the cases where the strings are identical and contain a repeated letter.
Those ones are buddies if you (invisibly) swap the repeated letters - as in Example 4 above.
For the remaining cases, we can step along the strings, comparing corresponding letters. If we find a mismatch (say 'a' and 'b'), we keep going until we find an opposite mismatch ('b' and 'a'). That is a potential 'true' result but we have to keep comparing to the end of the string in case there is 3rd mismatch.
Note that challenge does not state that the strings contain only letters, although
only letters may be swapped. So, for example, 12345
and 12435
are not buddies.
The code is perhaps surprisingly long, but it does do a single pass and short-circuits out as soon as it finds a 3rd mismatch between the strings, which cannot occur between buddies.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2025-07-21 use utf8; # Week 331 - task 2 - Buddy strings use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; use Encode; buddy_strings('luck', 'lcuk'); buddy_strings('love', 'love'); buddy_strings('feed', 'feed'); buddy_strings('enchilada', 'anchilade'); buddy_strings('3 blind mice', '3 clind mibe'); buddy_strings('12345', '12435'); sub buddy_strings { my ($one, $two, $length, $result, $j, $char1, $char2, $mismatch, %seen); # initialise ($one, $two) = @_; # loop over corresponding chars in each string $length = length($one); $result = 'false'; if ($length == length($two)) { for $j (0 .. $length - 1) { $char1 = substr($one, $j, 1); $char2 = substr($two, $j, 1); # swapped chars must be letters next unless ($char1 . $char2) =~ m|[a-z]{2}|i; # if they differ if ($char1 ne $char2) { # this is the first mismatch, so save it unless (defined $mismatch) { $mismatch = $j; # this is the second mismatch, so can it swap with the first? } elsif ($result eq 'false') { if ($char1 eq substr($two, $mismatch, 1) and $char2 eq substr($one, $mismatch, 1)) { $result = qq[true - '$char1' and '$char2']; } # this is a 3rd mismatch so not buddies } else { $result = 'false'; last; } } } # check for identical strings with (any) repeated letter if ($one eq $two) { for $j (0 .. $length - 1) { $char1 = substr($one, $j, 1); if ($seen{$char1}) { $result = qq[true - '$char1' and '$char1']; last; } $seen{$char1} = 1 if $char1 =~ m|[a-z]|; } } } say qq[\nInput: \$source = '$one', \$target = '$two']; say qq[Output: $result]; }
Input: $source = 'luck', $target = 'lcuk' Output: true - 'c' and 'u' Input: $source = 'love', $target = 'love' Output: false Input: $source = 'feed', $target = 'feed' Output: true - 'e' and 'e' Input: $source = 'enchilada', $target = 'anchilade' Output: true - 'a' and 'e' Input: $source = '3 blind mice', $target = '3 clind mibe' Output: true - 'c' and 'b' Input: $source = '12345', $target = '12435' Output: false
Any content of this website which has been created by Peter Campbell Smith is in the public domain