2

I am studying algorithm for my next interview, And i found this problem.

Which was asked by Facebook

Here's the problem.


Given the mapping a = 1, b = 2, ... z = 26, and an encoded message, count the number of ways it can be decoded.

For example, the message '111' would give 3, since it could be decoded as 'aaa, 'ka', and 'ak'.


I think I can handle with the mapping and converting to alphabet part. But making combinations is not easy for me.

Consider that it took me several hours to come up with this code below.

function combinations(str) {
var fn = function(active, rest, a) {

    // if nothing, just return
    if (!active && !rest)
        return;


    // there is nothing left in rest add active to A
    if (rest.length == 0) {
        a.push(active);
    } else {

        // append first number of rest to the end of the active item
        // [1] + 1 => 111
        // [1,2] + [3,4] = [1,2,3] + [4]
        if (rest.length > 0){
            fn(active.concat(rest[0]), rest.slice(1), a);
        }else {}


        // join 

        fn((active+rest[0]).split(","), rest.slice(1), a);
    }
    return a;
  }
  return fn([], str, []);
}

// run it
combinations(1,2,3);

I only got this.

[ [ 1, 2, 3 ],
[ '1', '23' ],
[ '12', 3 ],
[ '123' ],
[ '1', 2, 3 ],
[ '1', '23' ],
[ '12', 3 ],
[ '123' ] ]

See the duplicate item. I think I can now divide by 2 and get answers I want. Still it is not really a good answer.

Can you make it into better code?

Thank you


The code above is almost from this link

Dennis Lee
  • 23
  • 3
  • If its character decoding, how can you have `123`? – Rajesh Jan 10 '18 at 04:59
  • Since OP is looking for algorithm and not JS specific implementation, different language(*JS vs Java in dupe*) should not be considered. – Rajesh Jan 10 '18 at 05:09
  • That's correct @Rajesh This [post](https://stackoverflow.com/questions/20342462/review-an-answer-decode-ways) has an answer to this problem in other languages. (I just prefer js, that's what I do.) If you want, You can check js version of the answer below. – Dennis Lee Jan 11 '18 at 14:28

3 Answers3

4

In this case, we don't need to actually create the combinations in order to count them. We can use dynamic programming.

Let f(i) represent the number of valid ways to decode the message in string, S, up to and including the character at index i (zero-based). Then:

f(0)  = 1
f(i)  =
   if S[i] > 6 or S[i-1] > 2:
     // Nothing changes, we just
     // added a letter
     f(i-1)

   else:
     // All the ways to decode
     // up to (i-1) plus all the
     // ways to decode up to (i-2)
     // (let f(-1) equal 1)
     f(i-1) + f(i-2)

Example:

S = "123"

f(0) = 1
f(1) = f(0) + f(-1) = 2
f(2) = f(1) + f(0) = 3

The complexity of this process is O(n) time and O(1) space.

גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • Brilliant idea. Thanks! @גלעד ברקן, I 've changed into javascript version below. – Dennis Lee Jan 11 '18 at 01:32
  • It is a great answer, but I am wondering why S[i-1] should be more than 3? For example, "133" should produce 2 results "13 3" and "1 3 3", not 3. – krvss Jul 08 '18 at 00:08
  • Yes, this is what I've verified to be right. Thanks again for a nice solution @גלעדברקן! – krvss Jul 08 '18 at 01:33
0

I changed @גלעד ברקן answer into javascript, Hope it doesn't break anything, And I think it is working.

const Number = 11222;
let sum = 0;

const AlphabetGen = (i) => {

if(i == 0 ){
    sum =+ 1;
}else if ((Number[i] > 6) || (Number[i-1] > 3)){

    sum =+ AlphabetGen(i-1);
}else if(i > 0){
    if(i > 1){
        sum =+ AlphabetGen (i-1) + AlphabetGen(i-2);

    }else if (i == 1){
        sum =+ AlphabetGen (0) + 1
    }

}

return sum;
};

console.log(AlphabetGen(4));
Dennis Lee
  • 23
  • 3
  • Your answer cannot be edited but here : }else if ((Number[i] > 6) || (Number[i-1] > 3)){ should be instead }else if ((Number[i] > 6) || (Number[i-1] > 2)){ – Carmine Tambascia Aug 12 '19 at 13:35
0

My take on this using simple interator in JavaScript:

let processString = ( message, possibleWays = 0 ) => {
  if ( message.length ) {
    // First decode using single digit.
    // Shorten string by one and process again.
    possibleWays = processString( message.slice( 1 ,message.length), possibleWays );

    // Then check if current digit can be combined
    // with the next digit for cases like '11' for J, '12' for K, etc.
    const numCurr = parseInt( message[0] );
    const numNext = "undefined" === typeof message[1] ? null : parseInt(message[1]);

    if ( numCurr && numNext
        && numCurr < 3 // first digit can't be more that 2 as 26 letter max.
        && ( numCurr + numNext ) < 27 // sum of two should be < 26 as 26 letter max.
    ) {
      // Shorten string by two and process again.
      possibleWays = processString( message.slice( 2 ,message.length), possibleWays );
    }
  } else {
    // Reached end of the string: + 1 possible way to decode it.
    possibleWays++;
  }

  return possibleWays;
}

console.log( 'Total number of decoding possbilities: ' + processString('12325') );
Pavot
  • 870
  • 10
  • 8