28 November 2022

All the binaries and find the odd man out

All the binaries

We are asked to find all the binary numbers 'of length $n'. The examples show that 'length $n' means 'containing n digits' and that the desired solution includes those with leading zeroes.

These numbers are simply all the integers from 0 to 2^$n - 1, and we can simply loop over that range, outputting the numbers in binary format using sprintf's binary option.  It looks a little odd:

sprintf("%0${n}b", $_)

but if, say $n == 4, that amounts to 

sprintf("%04b", $_)

which means 4 binary digits with leading zeroes.

Find the odd man out

We are given a list of strings, such as:

"adc", "wzy", "abc"

From each of these strings we are to form a 'difference array', which contains the alphabetical distance of each letter in the string from the preceding one. So for "adc" the difference array is (3, -1) because 'd' is 3 letters after 'a' in the alphabet, and c is 1 letter before 'd'.

Mohammad suggests that we do this by assigning 0 to 'a', 2 to 'b' and so on, but as we are only concerned by differences we can simply use the ASCII values of the characters, which Perl provides in the function ord().

We are then to told that all of the strings bar one have the same difference array, and asked to find the one that does not. Curiously, perhaps, that is mildly challenging, but here is the solution I adopted.

First, let's represent the difference array not as an array but as a string. So for "adc" I am forming the difference array as the string '3, -1'. Let's call that the difference string.

So now I'm going through all the strings in the list, and for each one ($s) I create a difference string ($diff), and then with each difference string I do this:

$seen{$diff} .= qq[$s=];

The '=' is simply a separator, because I am concatenating all the '$s=' that have the same $diff into a single member of %seen.  It will end up looking like this:

$seen{'3, -1'} -> 'adc=wzy='
$seen{'1, 1'}  -> 'abc='

I then loop over the elements of %seen and look for the value that matches:

$seen{$s} =~ m|^([^=]*)=$|

or in words, a value that starts with a run of characters not containing '=' followed by '=' followed by nothing else.  If you look at the values of %seen shown above, you'll see that the only one that matches that pattern (ie having a single '=') is the odd one out.

This only works if Mohammad's assertions are correct, that is, there is only one odd man, all the strings are the same length and only contain lower case a-z letters. I could (and would in real life) have tested that those assumptions were correct.


No comments:

Post a Comment