A message containing letters from
A-Z
is being encoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message
"12"
,
it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding
"12"
is 2.My Answer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | /** * analysis: * I thought it is multiplication, then since it adds up conditionally, so better * go with basic addition * 1. the numbers that can have two meanings * 22, {BB,W} * 222, {BBB,BW,WB} * ~~~position i-2+22 or i-1+2 when i-1 and i compose a number between 11 and 26 (except 20) * 2222, {BBWW,WW,(up to here is position i-1 to current position)BBBB,BWB,WBB(these three are transitioning from position i-1)} * 22222 this would be all ways from position i-1 and i-2 if last number has position i * so general formular ways[i]=ways[i-1+ways[i-2] * it is possible to start from two previous position to transit to current position, because number here is just either 1 digit or 2 digits * * 2.if a position has number bigger than 2, then there is only one way to map back to letter * 2234 * 34 is not possible, so it has to be 223(remains all possible combinations) and 4, equivalent to number of ways of 223 * here i0=1,i1=2,i2=3, i3 is still 3 * * 3. 0 * leading 0 is impossible and means wrong input, return 0. mainly because the map has no 0 in it * 0,00, 30, 301(30,1 or 3,01 are all invalid) * * @author Andrew * */ public class Solution { public static int numDecodings(String s) { ///"","0","00", leading with 0 if (s == null || s.length() == 0 || "0".equals(s.substring(0, 1))) { return 0; } //2,08 if (s.length() == 1) return 1; int[] ways = new int[s.length()]; char prevChar, curChar; int curNum; ways[0] = 1; ways[1] = 1; //for string longer than 2, figure out the first 2 positions possible combinations //this might be able to be integrated to the following loop if (s.length() >= 2) { //impossible situations: 30, 40, only 0 has this problem because it is not in the map if (s.charAt(0) > '2' && s.charAt(1) == '0') ways[1] = 0; //10 and 20 are valid, and they has only one possible decoding way else if ((s.charAt(0) == '1' || s.charAt(0) == '2') && s.charAt(1) == '0') ways[1] = 1; //all other numbers such as 11,22 26 are having 2 possible decodings else if (Integer.parseInt(s.substring(0, 2)) > 10 && Integer.parseInt(s.substring(0, 2)) <= 26) ways[1] = 2; } //starting form third position because my basic assumption is ways[i]=ways[i-1]+ways[i-2] for (int i = 2; i < s.length(); i++) { prevChar = s.charAt(i - 1); curChar = s.charAt(i); curNum = Integer.parseInt("" + prevChar + curChar); //for 20 and 10(0 is position i),i-1 has only one possibility, so it equals ways at i-2 //this handles numbers between 1-10 in two positions if (curChar == '0') { ways[i] = ((prevChar == '2' || prevChar == '1') ? ways[i - 2] : 0); ways[i - 1] = ways[i]; //i-1 should be same as i } //this is for numbers that has two possible ways to decode else if (curNum > 10 && curNum <= 26) ways[i] = ways[i - 2] + ways[i - 1]; else //other situation has only 1 possible way to decode, so current ways of decoding is //equals to previous ways of decoding ways[i] = ways[i - 1]; } return ways[s.length() - 1]; } public static void main(String[] args) { // System.out.println(numDecodings("99") ); // System.out.println(numDecodings("27") ); // System.out.println(numDecodings("301") ); // System.out.println(numDecodings("08") ); System.out.println(numDecodings("110")); System.out.println(numDecodings("920")); System.out.println(numDecodings("20")); } } Test cases: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import static org.junit.Assert.*; import org.junit.Test; public class WaysDecodeTest { @Test public void testNumDecodings1() { int actual = Solution.numDecodings("99"); assertEquals(1, actual); } @Test public void testNumDecodings2() { int actual = Solution.numDecodings("301"); assertEquals(0, actual); } @Test public void testNumDecodings3() { int actual = Solution.numDecodings("27"); assertEquals(1, actual); } @Test public void testNumDecodings4() { int actual = Solution.numDecodings("08"); assertEquals(0, actual); } @Test public void testNumDecodings5() { int actual = Solution.numDecodings("12"); assertEquals(2, actual); } @Test public void testNumDecodings6() { int actual = Solution.numDecodings("121"); assertEquals(3, actual); } @Test public void testNumDecodings7() { int actual = Solution.numDecodings("2222"); assertEquals(5, actual); } @Test public void testNumDecodings8() { int actual = Solution.numDecodings("22222"); assertEquals(8, actual); } @Test public void testNumDecodings9() { int actual = Solution.numDecodings("22229"); assertEquals(5, actual); } @Test public void testNumDecodings10() { int actual = Solution.numDecodings("222292"); assertEquals(5, actual); } @Test public void testNumDecodings11() { int actual = Solution.numDecodings("2222920"); assertEquals(5, actual); } @Test public void testNumDecodings12() { int actual = Solution.numDecodings("110"); assertEquals(1, actual); } @Test public void testNumDecodings13() { int actual = Solution.numDecodings("20"); assertEquals(1, actual); } } |
No comments:
Post a Comment