Problem Statement (Asked By Facebook)
Given the mapping a = 1, b = 2, …, z = 26, and an encoded message, count the number of possible ways to decode it.
For example, the message '111' would give 3, since it could be decoded as 'aaa', 'ka', and 'ak'.
You can assume that the messages are valid. For instance, '001' is not allowed.
Problem link: https://leetcode.com/problems/decode-ways/
Disclaimer: Try solving the problem on your own first! Use this solution only as a reference to learn and improve.
This problem is well-suited for a recursive approach. Let’s break it down by defining a recurrence to solve it. Here are some test cases to understand the logic:
"") is the base case, and it should return 1 since there’s one way to decode it: doing nothing."1" should return 1, as it can only be decoded as "a"."11" should return 2 since it can be decoded as "aa" or "k"."111" should return 3: "a" + "k""k" + "a""a" + "a" + "a"."011" or "602" should return 0 because no letter starts with 0.The recursive structure is as follows:
0, there’s no valid decoding.Here’s the recursive solution:
Approach 1:
public class DecodeWays {
    public static int numEncodings(String s) {
        if (s.startsWith("0")) {
            return 0;
        } else if (s.length() <= 1) {
            return 1;
        }
        int total = 0;
        if (Integer.parseInt(s.substring(0, 2)) <= 26) {
            total += numEncodings(s.substring(2));
        }
        total += numEncodings(s.substring(1));
        return total;
    }
    public static void main(String[] args) {
        System.out.println(numEncodings("111")); // Output: 3
        System.out.println(numEncodings("011")); // Output: 0
    }
}
 Approach 2:
Instead of making redundant recursive calls, we can use a bottom-up dynamic programming approach. We calculate the number of ways to decode the string from the end to the beginning and store intermediate results in a cache.
import java.util.HashMap;
import java.util.Map;
public class DecodeWays {
    public static int numEncodings(String s) {
        if (s.isEmpty() || s.startsWith("0")) {
            return 0;
        }
        Map<Integer, Integer> cache = new HashMap<>();
        cache.put(s.length(), 1); // Base case: empty string has 1 way to decode
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) == '0') {
                cache.put(i, 0);
            } else {
                cache.put(i, cache.get(i + 1));
                if (i + 1 < s.length() && Integer.parseInt(s.substring(i, i + 2)) <= 26) {
                    cache.put(i, cache.get(i) + cache.get(i + 2));
                }
            }
        }
        return cache.get(0);
    }
    public static void main(String[] args) {
        System.out.println(numEncodings("111")); // Output: 3
        System.out.println(numEncodings("011")); // Output: 0
        System.out.println(numEncodings("226")); // Output: 3
    }
}
 2. Dynamic Programming Approach:
cache (map) to avoid recalculating.Time Complexity: O(n), where n is the length of the string.
Space Complexity: O(n) for the cache.
Did this solution help you understand the concept better? Let me know your thoughts in the comments below! Don’t forget to follow us on Instagram @coderz.py for more DSA tips and solutions to ace your coding interviews.
A design pattern is a reusable solution to a commonly occurring problem in software design. They…
Factory Method is a creational design pattern that deals with the object creation. It separates…
You are given two singly linked lists that intersect at some node. Your task is…
A builder plans to construct N houses in a row, where each house can be…
Find the length of the longest absolute path to a file within the abstracted file…
You manage an e-commerce website and need to keep track of the last N order…