You have intercepted a secret message encoded as a string of numbers. The message is decoded via the following mapping:
"1" -> 'A'
"2" -> 'B'
...
"25" -> 'Y'
"26" -> 'Z'
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:
"AAJF"
with the grouping (1, 1, 10, 6)
"KJF"
with the grouping (11, 10, 6)
(1, 11, 06)
is invalid because "06"
is not a valid code (only "6"
is valid).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 test cases are generated so that the answer fits in a 32-bit integer.
Example 1:
Input: s = "12"
Output: 2
Explanation:
"12" could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Explanation:
"226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Example 3:
Input: s = "06"
Output: 0
Explanation:
"06" cannot be mapped to "F" because of the leading zero ("6" is different from "06"). In this case, the string is not a valid encoding, so return 0.
Constraints:
1 <= s.length <= 100
s
contains only digits and may contain leading zero(s).When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to decoding a message is like trying every single possible way to break it down. We check each potential decoding to see if it makes sense according to the rules.
Here's how the algorithm would work step-by-step:
def decode_ways_brute_force(encoded_message):
def number_of_ways_to_decode(index):
# If we reach the end of the string, it's one valid way
if index == len(encoded_message):
return 1
# If we start with a zero, it's not a valid encoding
if encoded_message[index] == '0':
return 0
number_of_ways = 0
# Try decoding one digit
number_of_ways += number_of_ways_to_decode(index + 1)
# Try decoding two digits if possible
if index + 1 < len(encoded_message):
two_digit = int(encoded_message[index:index + 2])
# Must be between 10 and 26 inclusive
if 10 <= two_digit <= 26:
number_of_ways += number_of_ways_to_decode(index + 2)
return number_of_ways
return number_of_ways_to_decode(0)
The best way to solve this problem is to work backwards. Instead of figuring out how many ways to decode the entire message from the beginning, figure out how many ways to decode the last few characters and build up from there, reusing previous calculations.
Here's how the algorithm would work step-by-step:
def decode_ways(encoded_message):
message_length = len(encoded_message)
# Initialize array to store number of ways to decode
number_of_ways = [0] * (message_length + 1)
number_of_ways[message_length] = 1
# Iterate backwards through the encoded message
for index in range(message_length - 1, -1, -1):
# If the digit is '0', there are no ways to decode
if encoded_message[index] == '0':
number_of_ways[index] = 0
else:
# Add ways to decode from next index
number_of_ways[index] = number_of_ways[index + 1]
# Check if a two-digit combination is possible
if index + 1 < message_length and (encoded_message[index] == '1' or (encoded_message[index] == '2' and int(encoded_message[index + 1]) <= 6)):
# Add the number of ways from two indices ahead
number_of_ways[index] += number_of_ways[index + 2]
# The first value contains total possible ways
return number_of_ways[0]
Case | How to Handle |
---|---|
Null or empty input string | Return 1, as an empty string has one way to decode (no characters). |
Input string starts with '0' | Return 0, as no letter maps to '0' directly, thus it cannot be the start of a valid decoding. |
Input string contains '0' in the middle which is not preceded by '1' or '2' | Return 0, because '0' cannot be decoded alone and it's not part of a valid two-digit combination. |
Input string contains '10' or '20' | These are valid two-digit encodings, so handle them appropriately when calculating the number of ways. |
Input string contains '11' to '19' or '21' to '26' | These are valid two-digit encodings, so handle them appropriately when calculating the number of ways. |
Input string with only '0's after a valid starting sequence (e.g. 100, 200) | Return 0, as after the initial 10 or 20, the subsequent 0s cannot be decoded. |
Very long input string | Use dynamic programming to avoid redundant calculations and potential stack overflow issues from recursion, ensuring efficient scaling. |
Input string contains two-digit sequence greater than 26. | Treat the two digits as separate single-digit encodings in this case. |