计算给定映射可以解码消息的方式数

时间:2014-11-10 17:48:32

标签: python algorithm encoding python-2.x

所以我试图制作一个程序,打印出消息解码的方式。 可以在代码本身中轻松理解映射。现在它适用于大多数数字,但对于某些人来说,它并没有正确计算。例如数字1111,它解决它就像有两种方法解码它,但实际上有4种不同的方法。

这是我的代码:

mapping=["1", "2", "3", "4", "5", "6", "7" "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26"]

encodedCases = ["918", "739", "1142", "56", "82", "118", "1219", "6", "862", "1111"]

def decodeNumber(test, mapping):
    count=0
    checkFirstLast=0
    for i in range(9, len(mapping)):
        if mapping[i] in test:
            count+=1
        if test[:2]!=test[-2:]:
            if len(test)>3 and mapping[i] in test[:2]:
                checkFirstLast+=1
            elif len(test)>3 and mapping[i] in test[-2:]:
                checkFirstLast+=1

    if checkFirstLast==2:
        count+=1
    print count + 1

for test in encodedCases:
    test = test.strip()
    decodeNumber(test, mapping)

使用此方法我还没有找到一种方法可以正确地成功计算它。有没有更好的方法来实现这一目标?提前谢谢!

注意 - 映射是字母表的表示,为每个字母赋予其在字母表中的位置值。

3 个答案:

答案 0 :(得分:2)

我可以想到一种递归方法:

def decodeNumber(test):
    if not test: # check if test is empty
        return 1

    count = 0

    for i in mapping:
        if test.startswith(i):
            count += decodeNumber(test[len(i):])

    return count


for test in encodedCases:
    test = test.strip()
    print test, "==>" , decodeNumber(test)

decodeNumer检查test输入是否以映射中的条目开头。对于它所做的所有条目,它自己调用。新参数为test[len(i):],表示test,条目从开头删除。

例如,让test = "918":当i == "9"和新参数test[len("9"):]等于" 18"时,if语句首次评估为真。

总计数计算为消耗完整输入的路径总数。

答案 1 :(得分:1)

这是一个干净的动态编程方法,它在最坏情况下运行时间O(nk),其中k是映射的长度,n是字符串的长度。特别是,与天真的递归方法不同,它不会在输入上采用指数时间。

这适用于Python 3.2 +。

import functools

@functools.lru_cache(None) # lru_cache implements memoization
def decodeNumber(s, mapping):
    if not s:
        return 1 # base case: there's one way to decode the empty string

    # iterate over all possible prefixes, and count the ways to decode the resulting suffixes
    res = 0
    for m in mapping:
        if s.startswith(m):
            res += decodeNumber(s[len(m):], mapping)
    return res

请注意,mapping在此实现中应该是tuple(您也可以省略函数声明中的mapping参数以使用全局mapping变量。

Memoization使我们不必重复计算相同的值。如果没有memoization,算法必须至少执行res个递归调用(因为每个计算的解码必须以最终的return 1情况递归调用结束)。通过memoization,我们可以跳过已经处理过的递归调用。

如果您尝试使用和不使用memoization运行decodeNumber("1" * 256, ("1", "11")),则可以看到差异。没有记忆就永远不会完成。通过记忆,结果是即时的。

答案 2 :(得分:0)

这是一个O(n)时间复杂度(一次通过)和O(1)空间复杂度的迭代解决方案:

def ways(s):

if (len(s)==0 or len(s)==1): return 1

if (int(s[0:2])<27): prev = 2
else: prev = 1
prevprev = 1

for i in range(2,len(s)):
    if (int(s[i-1:i+1])<27): curr = prev + prevprev
    else: curr = prev
    prevprev = prev
    prev = curr
return prev

这是一种动态编程方法。在每次迭代中,添加另一个数字并计算直至该数字为止的消息解码方式。如果前面的数字和当前的数字大于26,则当前的数字与前面的数字相同,因为当前的数字必须是自己的数字。否则,对消息进行编码的方式等于不对消息进行编码的方式(不带前两者),再对不对消息进行编码的方式(对上)。

还有1111(1-1-1-1、1-1-11、1-11-1、11-1-1、11-11)的5种解码方式