LeetCode 91. Decode Ways

There are two ways to solve this problem. One is to solve it front-back, the other is back-front.

I currently only wrote the back-front method:

Suppose we have such a string:    a0, a1, a2.... ai, ai+1, ai+2...an-1

Suppose we have get that from an-1, an-2...ai+2, the ways of decoding such a sequence is dp[i+2]

There are three conditions to consider:

1: if ai == 1, we dont need to care about ai+1, the ways to decode is 1+ dp[i+2];

2: if ai == 2, ai+1 should be smaller than '6', the ways to decode is 1 + dp[i+2].

3: if ai == 2, ai+1 greater than '6', the ways to decode is dp[i+1].

Think that, decode a individual number is 1, but 0 has no way to decode, thus, 0.

So, we can have the dynamic function:  dp[i] = dp[i] + dp[i+2] if(s[i] == 1 || s[i] == 2 && s[i + 1] < '6')

#include <string>
#include <vector>
#include <iostream>
using namespace std;

/*
  A message containing letters from A-Z is being encoded to numbers using the following mapping:
  'A' --> 1
  'B' --> 2
  ....
  'Z' --> 26
  Given 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" or "L". 
  The number of ways decoding "12" is 2.
*/
/*
  Analyze: 
  Several example will make this question clear.
  "102" --> "10", "2" -> total method is 1
  "12" --> {"1", "2"}, "12" --> total method is 2.
  "127" --> {"1", "2", "7"}, {"12", "7"} --> total method is 2
  "126" --> {"1", "2", "6"}, {"12", "6"}, {"1", "26"}--> total method is 3.
  There are several cases need special attentions.
  1: "1"/"2" + "0", the char "0" can be interpreted as a decode way.
  2: "2" + "7, 8, 9" can only be interpreted as one way.
*/

int numDecodings(string s) {
  int n = s.size();
  vector<int> dp(n+2, 1);
  for(int i = s.size() - 1; i >= 0; --i) {
    if(s[i] == 0) dp[i] = 0;
    else dp[i] = dp[i + 1];

    if(i + 1 < s.size() && (s[i] == '1' || (s[i] == '2' && s[i+1] <= '6'))) {
      dp[i] += dp[i+2];
    }
  }
  return dp[0];
}



int main(void) {
  cout << "123" << " decode ways: "<< numDecodings("123") << endl;
  cout << "102" << " decode ways: "<< numDecodings("102") << endl;
  cout << "127" << " decode ways: "<< numDecodings("127") << endl;
}


To visualize the problem.... Everytime, we can decode two chars or one chars.


'0' is a special case to case, there are two cases that we might encounter '0'.  However, no matter where we have 0, the corresponding decode way will 0.

#include <string>
#include <vector>
#include <iostream>
using namespace std;
// decode it from back to front.
int decodeWays(string str, int len) {
  if(len == 0 || len == 1) return 1;
  int num = 0;
  if(str[len - 1] > '0') // this line should be commented out! for the case "10000000" == 1
    num = decodeWays(str.substr(0, len - 1), len - 1);
  if(str[len - 2] == '1' || ((str[len - 2] == '2') && str[len - 1] < '6'))
    num += decodeWays(str.substr(0, len - 2), len - 2);
  return num;
}

// dp
int decodeWaysII(string str) {
  int n = str.size();
  vector<int> dp(n + 1, 0);
  dp[0] = dp[1] = 1;
  for(int i = 2; i <= n; ++i) {
    if(str[i - 1] > '0') {
      dp[i] = dp[i-1];
    }
    if(str[i-2] == '1' || (str[i-2] == '2' && str[i-1] < '6'))
      dp[i] += dp[i-2];
  }
  return dp[n];
}

// to simplify more
int decodeWaysIII(string str) {
  int n = str.size();
  if(n <= 1) return 1;
  int prev = 1;
  int curr = 1;
  int sum = 0;
  for(int i = 2; i <= n; ++i) {
    if(str[i-1] == '0') prev = 0;
    if(str[i-2] != '1' && !(str[i-2] == '2' && str[i-1] < '6'))
      curr = 0;
    sum = curr + prev;
    prev = curr;
    curr = sum;
  }
  return curr;
} 


Another ways is more cool! and space efficient!

// In-place ways
int decodeWays(string str) {
  if(str[0] == '0') return 0;
  int prev = 0;
  int curr = 1;
  for(int i = 1; i <= str.size(); ++i) {
    if(s[i-1] == '0') curr = 0;
    if(i < 2 || !(s[i-2] == '1' || (s[i-2] == '2' && s[i-1] <= '6')))
      prev = 0;

    int tmp = curr;
    curr = curr + prev;
    prev = tmp;
  }
  return curr;
}

reference: http://www.acmerblog.com/leetcode-solution-decode-ways-6209.html

Another variation: Asked by Amazon,  return all the decoded strings, better to use backtracking, the time complexity is T(n) = T(n-1) + T(n-2) Thus it is 2^N

#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
using namespace std;

void decodeWays(string str, int pos, string path, vector<string>& res, unordered_map<string, char>& dict) {
  if(pos > str.size()) return;
  if(pos == str.size()) {
    res.push_back(path);
    return;
  }
  for(int i = 1; i <= 2; ++i) {
    string tmp = str.substr(pos, i);
    if(dict.count(tmp)) {
      decodeWays(str, pos + i, path + dict[tmp], res, dict);
    }
  }
}

vector<string> decodeWays(int input, unordered_map<string, char>& dict) {
  string str = to_string(input);
  if(str.size() == 0) return {};
  vector<string> res;
  string path = "";
  decodeWays(str, 0, path, res, dict);
  return res;
}
int main(void) {
  unordered_map<string, char> dict {
    {"1", 'A'},
    {"2", 'B'},
    {"3", 'C'},
    {"4", 'D'},
    {"5", 'E'},
    {"6", 'F'},
    {"7", 'G'},
    {"8", 'H'},
    {"9", 'I'},
    {"10", 'J'},
    {"11", 'K'},
    {"12", 'M'},
    {"13", 'N'},
    {"14", 'O'},
    {"15", 'P'},
    {"16", 'Q'},
    {"17", 'R'},
    {"18", 'S'},
    {"19", 'T'},
    {"20", 'U'},
    {"21", 'V'},
    {"22", 'W'},
    {"23", 'X'},
    {"24", 'Y'},
    {"25", 'Z'}};
  vector<string> res = decodeWays(123, dict);
  for(int i = 0; i < res.size(); ++i) cout << res[i] << endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值