perl logo Perl logo (Thanks to Olaf Alders)

The weekly challenge 370 - Task 2: Scramble String

  1 #!/usr/bin/env perl
  2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-370/#TASK2
  3 #
  4 # Task 2: Scramble String
  5 # =======================
  6 #
  7 # You are given two strings A and B of the same length.
  8 #
  9 # Write a script to return true if string B is a scramble of string A otherwise
 10 # return false.
 11 #
 12 # String B is a scramble of string A if A can be transformed into B by a single
 13 # (recursive) scramble operation.
 14 #
 15 # A scramble operation is:
 16 #
 17 ## - If the string consists of only one character, return the string.
 18 ## - Divide the string X into two non-empty parts.
 19 ## - Optionally, exchange the order of those parts.
 20 ## - Optionally, scramble each of those parts.
 21 ## - Concatenate the scrambled parts to return a single string.
 22 #
 23 ## Example 1
 24 ##
 25 ## Input: $str1 = "abc", $str2 = "acb"
 26 ## Output: true
 27 ##
 28 ## "abc"
 29 ## split: ["a", "bc"]
 30 ## split: ["a", ["b", "c"]]
 31 ## swap: ["a", ["c", "b"]]
 32 ## concatenate: "acb"
 33 #
 34 ## Example 2
 35 ##
 36 ## Input: $str1 = "abcd", $str2 = "cdba"
 37 ## Output: true
 38 ##
 39 ## "abcd"
 40 ## split: ["ab", "cd"]
 41 ## swap: ["cd", "ab"]
 42 ## split: ["cd", ["a", "b"]]
 43 ## swap: ["cd", ["b", "a"]]
 44 ## concatenate: "cdba"
 45 #
 46 ## Example 3
 47 ##
 48 ## Input: $str1 = "hello", $str2 = "hiiii"
 49 ## Output: false
 50 ##
 51 ## A fundamental rule of scrambled strings is that they must be anagrams.
 52 #
 53 ## Example 4
 54 ##
 55 ## Input: $str1 = "ateer", $str2 = "eater"
 56 ## Output: true
 57 ##
 58 ## "ateer"
 59 ## split: ["ate", "er"]
 60 ## split: [["at", "e"], "er"]
 61 ## swap: [["e", "at"], "er"]
 62 ## concatenate: "eater"
 63 #
 64 ## Example 5
 65 ##
 66 ## Input: $str1 = "abcd", $str2 = "bdac"
 67 ## Output: false
 68 #
 69 ############################################################
 70 ##
 71 ## discussion
 72 ##
 73 ############################################################
 74 #
 75 # We recursively build all possible scrambles of $str. We then check
 76 # each of those for wether it matches $str2 and return true if that's
 77 # the case. In the end, we didn't find any scramble that matches $str2,
 78 # so we return false.
 79 
 80 use v5.36;
 81 
 82 scramble_string("abc", "acb");
 83 scramble_string("abcd", "cdba");
 84 scramble_string("hello", "hiiii");
 85 scramble_string("ateer", "eater");
 86 scramble_string("abcd", "bdac");
 87 
 88 sub scramble_string($str1, $str2) {
 89     say "Input: \"$str1\", \"$str2\"";
 90     my @scrambled = find_scrambles($str1);
 91     foreach my $scr (@scrambled) {
 92         return say "Output: true" if $scr eq $str2;
 93     }
 94     say "Output: false";
 95 }
 96 
 97 sub find_scrambles($str) {
 98     return ($str) if length($str) == 1;
 99     my @result = ();
100     foreach my $i (1..length($str)-1) {
101         my $l = substr($str, 0, $i);
102         my $r = substr($str, $i);
103         my @left = find_scrambles($l);
104         my @right = find_scrambles($r);
105         foreach my $left (@left) {
106             foreach my $right (@right) {
107                 push @result, $left . $right;
108                 push @result, $right . $left;
109             }
110         }
111     }
112     return @result;
113 }