perl logo Perl logo (Thanks to Olaf Alders)

The weekly challenge 317 - Task 2: Friendly Strings

 1 #!/usr/bin/env perl
 2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-317/#TASK2
 3 #
 4 # Task 2: Friendly Strings
 5 # ========================
 6 #
 7 # You are given two strings.
 8 #
 9 # Write a script to return true if swapping any two letters in one string match
10 # the other string, return false otherwise.
11 #
12 ## Example 1
13 ##
14 ## Input: $str1 = "desc", $str2 = "dsec"
15 ## Output: true
16 #
17 #
18 ## Example 2
19 ##
20 ## Input: $str1 = "fuck", $str2 = "fcuk"
21 ## Output: true
22 #
23 #
24 ## Example 3
25 ##
26 ## Input: $str1 = "poo", $str2 = "eop"
27 ## Output: false
28 #
29 #
30 ## Example 4
31 ##
32 ## Input: $str1 = "stripe", $str2 = "sprite"
33 ## Output: true
34 #
35 ############################################################
36 ##
37 ## discussion
38 ##
39 ############################################################
40 #
41 # There is a pretty simple solution to this problem that just needs
42 # to take care of a few corner cases.
43 # 1. If the length of the two strings doesn't match, we can return false
44 # 2. We walk both strings simultaneously. If the two strings happen to
45 #    be equal everywhere except for two places, and the characters in
46 #    those two places are just exchanged, we can return true
47 # 3. The missing corner case: if the two strings are actually the same,
48 #    but have at least one duplicate character, we can also return true. If
49 #    they are the same without duplicate characters, we can't swap two
50 #    characters to make the strings match, so we return false.
51 
52 use v5.36;
53 
54 friendly_strings("desc", "dsec");
55 friendly_strings("fuck", "fcuk");
56 friendly_strings("poo", "eop");
57 friendly_strings("stripe", "sprite");
58 friendly_strings("foo", "foo");
59 friendly_strings("bar", "bar");
60 
61 sub friendly_strings($str1, $str2) {
62     say "Input: '$str1', '$str2'";
63     return say "Output: false" if length($str1) != length($str2);
64     my @chars1 = split //, $str1;
65     my @chars2 = split //, $str2;
66     my $found_chars = {};
67     my @diff = ();
68     foreach my $i (0..$#chars1) {
69         $found_chars->{$chars1[$i]}++;
70         if($chars1[$i] ne $chars2[$i]) {
71             push @diff, [$chars1[$i], $chars2[$i]];
72         }
73     }
74     if(scalar(@diff) == 2) {
75         if($diff[0]->[0] eq $diff[1]->[1] && $diff[0]->[1] eq $diff[1]->[0]) {
76             say "Output: true";
77         } else {
78             say "Output: false";
79         }
80     } elsif (scalar(@diff) == 0) {
81         foreach my $char (keys %$found_chars) {
82             return say "Output: true" if $found_chars->{$char} > 1;
83         }
84         say "Output: false";
85     } else {
86         say "Output: false";
87     }
88 }