Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Exploring Backtracking and Memoization for Decoding Digit Strings
Feb 21, 2025
488 views
Written by Array Alchemist
LeetCode wizard with 75 conquered challenges under my belt.
Turning algorithm nightmares into "Aha!" moments, one explanation at a time.
Join me to level up your coding skills – from interviews to real-world application!
You have intercepted a secret message encoded as a string of numbers. The message is decoded via the following mapping:
However, while decoding the message, you realize that there are many different ways you can decode the message because some codes are contained in other codes ("2" and "5" vs "25").
For example, "11106" can be decoded into:
Note: there may be strings that are impossible to decode.
Given a string s containing only digits, return the number of ways to decode it. If the entire string cannot be decoded in any valid way, return 0.
The task is to count the number of ways to decode a string of digits into letters using the mapping:
A single digit (1-9) can be decoded into a letter.
Recursive Approach with Memoization
The provided solution uses recursion with memoization to efficiently count the number of valid decodings. Here's how it works:
Base Cases:
Recursive Cases:
Memoization:
function numDecodings(s) { // Edge case: If the string is empty or starts with '0', return 0 if (s.length === 0 || s[0] === '0') return 0; // Memoization map to store results of subproblems const memo = new Map(); // Start the recursive helper function from index 0 return helper(0);function helper(i) { Base case: If we've reached the end of the string, return 1 If the current character is '0', it cannot be decoded alone If the result for this index is already computed, return it Start with the result from decoding the current character as a single digit let result = helper(i + 1); If the current two characters form a valid number (10-26), add the result from decoding them Store the result in the memoization map Return the result }Top-down with memoization
function numDecodings(s) { if (s.length === 0 || s[0] === '0') return 0; const memo = new Map(); return helper(0); function helper(i) { if (i === s.length) return 1; if (s[i] === '0') return 0; if (memo.has(i)) return memo.get(i); let result = helper(i + 1); // Take one if (i + 1 < s.length && parseInt(s.substring(i, i + 2)) <= 26) { result += helper(i + 2); // Take two } memo.set(i, result); return result; } }Example Walkthrough (Flow for "123")
another way to solve using iterative approach:
numDecodings(s) { if (s.length === 0 || s[0] === '0') { return 0; } const n = s.length; const dp = new Array(n + 1).fill(0); // Empty string can be decoded in one way dp[0] = 1; // First character can be decoded in one way if it's not '0' dp[1] = 1; for (let i = 2; i <= n; i++) { const oneDigit = parseInt(s[i - 1], 10); const twoDigits = parseInt(s.substring(i - 2, i), 10); if (oneDigit >= 1 && oneDigit <= 9) { dp[i] += dp[i - 1]; } if (twoDigits >= 10 && twoDigits <= 26) { dp[i] += dp[i - 2]; } } return dp[n]; }#decoding #decode #leetcode #dynamicProgramming