1 Million Ways to Solve a Code Puzzle

Home / Technology / 1 Million Ways to Solve a Code Puzzle
I am exploring the concepts of refactoring and creating multiple solutions for a single challenge.

[vc_row][vc_column][vc_column_text]This morning, as I was looking through my inbox that admittedly had gotten a bit out of hand, I noticed I’d received a series of CodeSignal emails from a 14-day email challenge (one coding challenge per day). I decided to do the first one so I could see if it was something I felt like doing today.

You know what’s coming next, right? That’s right. Spoiler. Alert.[/vc_column_text][vc_column_text el_class=”spoiler”]

Spoiler Alert!

Challenge: isLucky

Directive:

Ticket numbers usually consist of an even number of digits. A ticket number is considered lucky if the sum of the first half of the digits is equal to the sum of the second half.

Given a ticket number n, determine if it’s lucky or not.

Input/Output Requirements:
    • [execution time limit] 4 seconds
    • [input] integer n – a ticket number represented as a positive integer with an even number of digits.
      Guaranteed constraints: 10 ≤ n < 106
    • [output] boolean – true if n is a lucky ticket number, false otherwise.
Solution #1:

When I first approached this problem, my initial thought was to split the input number into an array. Since I have done this a billion times with strings, I immediately converted the number into a string before splitting it. Then, while looping through the arrays, I converted the string back into a number so I could add each of the digits together. The solution wasn’t great but it worked.

function isLucky(n) {

    let numArr = n.toString();
    numArr.split('');
    let firstHalf = numArr.slice(0, numArr.length/2);
    let secondHalf = numArr.slice(numArr.length/2);
    let sumFirstHalf = 0;
    let sumSecondHalf = 0;

    for (let i = 0; i < firstHalf.length; i++) {
        sumFirstHalf = sumFirstHalf + parseInt(firstHalf[i]);
        sumSecondHalf = sumSecondHalf + parseInt(secondHalf[i]);
    }
    if (sumFirstHalf === sumSecondHalf) {
        return true;
    } else {
        return false;
    }
}
Solution #2 (Failed Attempt):

A little while later, I started wondering if there had been a better way to do this. I mean, I knew there probably was, so I figured it was a good time to think about refactoring the code to make it better. Good is good. But better is better. Obviously.

So the first thing I did was look at numArr. I knew I still wanted to use an array because it’s the simplest, most efficient way (that I know of) to split the number down the middle so I can add up the digits from each side. But why was I going through the trouble of turning the number into a string, just to split it into an array, to then convert it back to a number. That seems silly, doesn’t it?

So I changed the way I was created my array. Rather than converting the number a string, I tried to create the array directly from the number using let numArr = Array.from(n);. Then, since I no longer needed to convert the elements of the array back into an integer, I was able to remove both instances of the parseInt() methods from my code.

But this didn’t work. I ended up with an empty array and everything came back true. It turns out you can only create an array in this way if you are using array-like objects or iterable objects (like strings).

Solution #3:

Since it looked like there was no other way to convert the number into an array, I thought I might try adding in some high order functions to improve my code.

I started with the how I was converting the number into a string, then later back to a number. Rather than doing this separately, I set up my code so that it does it all at one time, first converting the string, then splitting it, and finally converting each element of the array back into an integer so it can later be added (without worrying about forgetting to do it).

let numArr = n.toString().split("").map(str => parseInt(str));

After that, I decided to take away the for loop that I used earlier and instead use the Array.reduce() method to add the digits and return the sum.

This is what my code looked like:

function isLucky(n) {

    let numArr = n.toString().split("").map(str => parseInt(str));

    let firstHalf = numArr.slice(0, numArr.length/2);
    let secondHalf = numArr.slice(numArr.length/2);
    let sumFirstHalf = firstHalf.reduce((a, b) => a + b);
    let sumSecondHalf = secondHalf.reduce((a, b) => a + b);

    if (sumFirstHalf === sumSecondHalf) {
        return true;
    } else {
        return false;
    }

}

It’s worth noting that I didn’t have to use the sumFirstHalf and sumSecondHalf variables. I could have put these statements directly into the arguments of my if statement and it would have worked exactly the same. I may have also used a ternary operator instead of my full-blown 5-line if statement.

How do I know this? Well…

Solution #4:
function isLucky(n) {

    let numArr = n.toString().split("").map(str => parseInt(str));

    let firstHalf = numArr.slice(0, numArr.length/2);
    let secondHalf = numArr.slice(numArr.length/2);

    return (firstHalf.reduce((a, b) => a + b) === secondHalf.reduce((a, b) => a + b)) ? true : false;

}

[/vc_column_text][vc_column_text]So there you have it — one very simple problem, estimated to take around 10 minutes to complete, and 3 working solutions. The first took a little over 9 minutes, the second (failed attempt) was another 10 since it involved doing a bit of research when it didn’t work, and the 3rd and 4th solutions were another 3-4 minutes each.

Important Lessons:

  1. There is more than one way to do things! Don’t be afraid to keep learning and exploring, even if you think you already have an acceptable solution.
  2. It takes time to refactor code, but the results can be well worth the time investment. Remember, good is good, but better is better. 😉

[/vc_column_text][/vc_column][/vc_row]

Let's chat!

%d bloggers like this: