您将收到一条仅包含数字的编码信息。您还可以获得以下映射
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'那样进行编码,只需返回。
能否更有效地解决这个问题?
答案 0 :(得分:21)
您当前对问题的近似是正确的。虽然,你需要非常小心,你正在处理所有不清楚的情况,这将使我的答案比你需要的时间长一些。
从Dynamic Programming的角度来看,查看此问题的正确方法。我们将您的输入字符串视为message
,其长度为n
。
要解码message
个n
个字符,您需要知道使用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 - 1
个n - 2
字符和ways[n]
字符的解码方式?
它实际上是以同样的方式。最终你会把它减少到基本情况。
让我们说message
它可以解码n
个ways[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;
}
}
示例返回
答案 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之间的字符有效。