给定编码消息,计算可以解码的方式的数量

时间:2013-03-23 11:10:40

标签: c string algorithm

您将收到一条仅包含数字的编码信息。您还可以获得以下映射

 A : 1
 B : 2
 C : 3
 ..
 Z : 26

给定编码消息,计算可以解码的方式数。

例如:12可以通过两种方式解码:(A,B)和(L)

我提出了接受数字作为字符串字符然后检查其每个数字的算法:

1.If the first digit of the string array is zero , return zero.

2.for each of its digit(i) from 1 to n perform:

   if str[i-1]>2 || (str[i-1]=='2' && str[i]>'6')
      return 0;

   if(str[i]==0)
      return 0;

每次我尝试将消息中的第一个数字编码为字母,或者如果可能的话,我可以将前两个数字编码成一个字母。如果没有办法像遇到单个'0'或遇到'32'那样进行编码,只需返回。

能否更有效地解决这个问题?

6 个答案:

答案 0 :(得分:21)

您当前对问题的近似是正确的。虽然,你需要非常小心,你正在处理所有不清楚的情况,这将使我的答案比你需要的时间长一些。

Dynamic Programming的角度来看,查看此问题的正确方法。我们将您的输入字符串视为message,其长度为n

要解码messagen个字符,您需要知道使用message个字符和n - 1使用message解码n - 2的方式有多少n个字符。也就是说,

1 1 2 3 4 5 6 8 9 0 1 +---+---+---+---+---+---+---+---+---+---+ message | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 | +---+---+---+---+---+---+---+---+---+---+ 个字符的消息。

message

长度使用1位数和n - 1 1 1 2 3 4 5 6 8 9 0 1 +---+---+---+---+---+---+---+---+---+ +---+ message | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | + | 2 | +---+---+---+---+---+---+---+---+---+ +---+ 个字符。

message

使用2位数和n - 2 1 1 2 3 4 5 6 8 9 0 1 +---+---+---+---+---+---+---+---+ +---+---+ message | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | + | 1 | 2 | +---+---+---+---+---+---+---+---+ +---+---+ 个字符。

message

现在,您可能会问自己:

  

如何计算n - 1n - 2字符和ways[n]字符的解码方式?

它实际上是以同样的方式。最终你会把它减少到基本情况。

让我们说message它可以解码nways[n]个字符的方式。然后,您可以以这种方式放置ways[n] = ways[n - 1] + ways[n - 2]

1

(因为不知道你如何定义空字符串的方式数量,我认为它是n = 0。)

有适当的约束和基本情况,

  • ways[n] = 1

    n > 1
  • message[n]message[n - 1:n]有效且ways[n] = ways[n - 1] + ways[n - 2] 有效,

    n > 1
  • message[n]message[n - 1:n]有效且ways[n] = ways[n - 1] 有效,

    n > 1
  • message[n]message[n - 1:n] 有效且ways[n] = ways[n - 2] 有效,

    ways[n] = 0
    
  • ,否则

    decode

C中的迭代int decode(char* message, size_t len) { int i, w, ways[] = { 1, 0 }; for(i = 0, w; i < len; ++i) { w = 0; if((i > 0) && ((message[i - 1] == '1') || (message[i - 1] == '2' && message[i] < '7'))) { w += ways[1]; } if(message[i] > '0') { w += ways[0]; } ways[1] = ways[0]; ways[0] = w; } return ways[0]; } 函数可能如下所示,

{{1}}

You can see it here at ideone.我正在使用恒定的额外内存进行计算。

答案 1 :(得分:1)

递归解决方案

int countdecodes(char * s)
{
    int r = 0;
    switch(*s)
    {
        case 0:
            return 1;
        case '0':
            return 0;
        case '1':
            r = countdecodes(s+1);
            if(*(s+1))
                r = r + countdecodes(s+2);
            return r;
        case '2':
            r = countdecodes(s+1);
            switch(*(s+1))
            {
                case '0': case '1': case '2':
                case '3': case '4': case '5':
                case '6':
                    r = r + countdecodes(s+2);
                default:
                    return r;
            }
        case '3': case '4': case '5': case '6':
        case '7':case '8': case '9':
            return countdecodes(s+1);
        default:
            return 0;
    }
}

示例返回

  1. countdecodes( “123”); //返回3
  2. countdecodes( “1230”); //返回0
  3. countdecodes( “1220”); //返回2
  4. countdecodes( “12321”); //返回6

答案 2 :(得分:0)

def nombre_codage(message):
map=[]
for i in range(1,27,1):
    map.append(i)
nbr=1
n=len(message)
pair_couple=0
for j in range (0,n,2):
    if int(message[j:j+2]) in map and len(message[j:j+2])==2:
        pair_couple+=1
nbr+=2**pair_couple-1 
impair_couple=0
for k in range (1,n,2):
    if int(message[k:k+2]) in map and len(message[k:k+2])==2:
        impair_couple+=1
nbr+=2**impair_couple-1    
return nbr 

这是python中的解决方案,它将消息作为字符串,然后计算可以编码并使用二项式系数的两个数字的位数-我使用了另一种形式(C(np)= 2 ^ n) -计算您可以使用多少种方式对邮件进行编码。

答案 3 :(得分:0)

我想用注释过的python代码补充@Alexander的帖子,因为我花了一些时间来弄清楚动态编程解决方案的工作原理。我发现认识到这与编码斐波那契函数有多么相似很有用。我还上传了full code, tests and runtime comparison with naive recursion on my github

def number_of_decodings_fast(code):
    """ Dynamic programming implementation which runs in 
    O(n) time and O(1) space. 
    The implementation is very similar to the dynamic programming
    solution for the Fibonacci series. """
    length = len(code)
    if (length <= 1):
        # assume all such codes are unambiguously decodable
        return 1
    else:
        n_prev = 1 # len 0
        n_current = 1 # len 1
        for i in range(1,length):
            if (
                # a '1' is ambiguous if followed by
                # a digit X=[1-9] since it could be
                # decoded as '1X' or '1'+'X'
                code[i-1]=='1' and 
                code[1] in [str(k) for k in (range(1,10))]
            ) or (
                # a '2' is ambiguous if followed by 
                # a digit X=[1-6] since it could be
                # decoded as '2X' or '2'+'X'
                code[i-1]=='2' and 
                code[i] in [str(k) for k in range(1,7)]
            ):
                # New number of decodings is the sum of
                # decodings obtainable from the code two digits back
                # (code[0:(i-2)] + '[1-2]X' interpretation)
                # and decodings obtainable from the code one digit back
                # (code[0:(i-1)] + 'X' interpretation).
                n_new = n_prev + n_current
            else:
                # New number of decodings is the same as
                # that obtainable from the code one digit back
                # (code[0:(i-1)] + 'X' interpretation).
                n_new = n_current
            # update n_prev and n_current
            n_prev = n_current
            n_current = n_new
        return n_current

答案 4 :(得分:0)

这是一个使用动态编程的小型且简单的 O(n)解决方案:

int ways(string s){
    int n = s.size();
    vector<int> v(n + 1, 1);
    v[n - 1] = s[n - 1] != '0';
    for(int i = n - 2; i >= 0; i--){
        if(s[i] == '0') {v[i] = v[i + 1]; continue;}
        if(s[i] <= '2' && s[i + 1] <= '6') 
            if(s[i + 1] != '0') v[i] = v[i + 1] + v[i + 2];
            else v[i] = v[i + 2];
        else v[i] = v[i + 1];
    }
    return v[0];
}

想法是逐个索引走。如果该索引(附加到下一个索引)包含小于或等于26的数字且不包含零,则将其分为2种可能性,否则仅分为一种。

ways("123");    //output: 3
ways("1230");   //output: 0
ways("1220");   //output: 2
ways("12321");  //output: 6

答案 5 :(得分:0)

对于这个具有O(N)时间复杂度和O(1)空间复杂度的问题,我有一个基于模式的简单解决方案。

说明示例:-

12312

                              1 
                     /                 \
                  1,2                   12
                /     \                   \
            1,2,3      1,23                12,3 
            |             |                    \
        1,2,3,1           1,23,1                12,3,1
        /    \           /       \             /       \
1,2,3,1,2   1,2,3,12   1,23,1,2   1,23,12   12,3,1,2   12,3,12


P1 P2 N  T
1  0  1  1
1  1  2  2
2  1  2  3
3  0  1  3
3  3  2  6

P1代表新元素未形成2位数数字的案例数

P2代表案例数,其中新元素形成2位数

N = 1代表与p1相关的情况,N = 2代表与p2相关的情况

关于情况1和2的新树就像

           1
       /       \
      1         2
   /     \       \
  1       2       1
  |       |       |
  1       1       1
 / \     / \     / \
1   2   1   2   1   2
#include <iostream>
#include <string>
using namespace std;


int decode(string s)
{
    int l=s.length();
    int p1=1;
    int p2=0;
    int n;
    int temp;
    for(int i=0;i<l-1;i++)
    {
        if(((int(s[i]-'0')*10)+int(s[i+1]-'0'))<=26)
        {
            n=2;
        }
        else
        {
            n=1;
        }
        temp=p2;
        p2=(n==2)?p1:0;
        p1=p1+t;
    }
    return p1+p2;
}

int main() {
    string s;
    getline(cin,s);
    cout<<decode(s);
    return 0;
}

仅对1到9之间的字符有效。