#include
using namespace std;
/*
QUESTION - https://www.youtube.com/watch?v=jFZmBQ569So&list=PL-Jc9J83PIiG8fE6rj9F5a6uyQ5WPdqKy&index=20 (Count the number of Encodings)
*/
void getEncodings(string digits, string path, vector < char > & encodings) {
//base case
//string is empty, which means we have processed all digits
if (digits.empty()) {
cout << path << '\n';
return;
}
//invalid case
//If the first char is '0', the prefixes formed by it will be invalid, i.e. '0' & "0i"
//eg "04356" => prefixes formed => oneChar = '0' & twoChar = "04" which are both invalid, so we can directly return
if (digits[0] == '0') {
return;
}
// levels - digits (the whole string)
// options - the starting 2 prefixes of digits
// one digit at a time
int oneChar = stoi(digits.substr(0, 1));
getEncodings(digits.substr(1), path + encodings[oneChar], encodings);
//two digits at a time
//we can only get a substring of 2 length if the string is atleast of length = 2
if (digits.size() >= 2) {
int twoChar = stoi(digits.substr(0, 2));
//We can only have this call if twoChar corresponds to a valid encoding
// substring of length 2, which is: 10 <= twoChar <= 26
if (twoChar >= 10 && twoChar <= 26) {
getEncodings(digits.substr(2), path + encodings[twoChar], encodings);
}
}
}
int getEncodingsMemo(string digits, vector < char > & encodings, unordered_map < string, int > & memo) {
/*
The only thing changing here is digits
So we should be able to memoise the code with a single key = digits.
Definition = memo(digits) = Number of encodings possible when string = digits.
*/
if (digits.empty()) {
return 1;
}
if (digits[0] == '0') {
return 0;
}
//memo Check
if (memo.count(digits) > 0) {
return memo[digits];
}
int totalEncodingsOneChar = 0, totalEncodingsTwoChar = 0;
//one digit at a time
int oneChar = stoi(digits.substr(0, 1));
totalEncodingsOneChar = getEncodingsMemo(digits.substr(1), encodings, memo);
//two digits at a time
if (digits.size() >= 2) {
int twoChar = stoi(digits.substr(0, 2));
// substring of length 2, which is: 10 <= twoChar <= 26
if (twoChar >= 10 && twoChar <= 26) {
totalEncodingsTwoChar = getEncodingsMemo(digits.substr(2), encodings, memo);
}
}
return memo[digits] = totalEncodingsOneChar + totalEncodingsTwoChar;
}
int getEncodingsDP(string & digits) {
/*
Storage & Meaning - dp[i] = Number of encodings possible for strings starting at index i (upto n - 1).
*/
int n = digits.size();
vector dp(n, 0);
/*
Direction - Smallest Problem at: dp[n - 1](string starting at index [n - 1] and ending at [n - 1])
Largest Problem at: dp[0] (String starting at index 0, original string)
*/
//edge case
dp[n - 1] = digits[n - 1] == '0' ? 0 : 1;
/*
Travel & Solve - Travel from smallest to largest problem to get the answer to original problem
*/
for(int i = n - 2; i >= 0; i--){
if(digits[i] != '0'){
dp[i] += dp[i + 1];
if(i <= n - 2){
int twoCharInt = stoi(digits.substr(i, 2));
if(twoCharInt >= 10 && twoCharInt <= 26){
dp[i] += i == n - 2 ? 1 : dp[i + 2];
}
}
}
}
return dp[0];
}
int main() {
// your code goes here
string digits;
cin >> digits;
vector < char > encodings(27, -1);
for (int i = 1; i <= 26; i++) {
encodings[i] = (char)(i - 1 + 'a');
}
//Recursive Call with print
//getEncodings(digits, "", encodings);
//Memo Call
// unordered_map < string, int > memo;
// cout << getEncodingsMemo(digits, encodings, memo) << '\n';
// cout << stoi("03") << '\n';
//DP Call
cout << getEncodingsDP(digits) << '\n';
}