如何应用回溯算法?

时间:2016-10-01 22:16:16

标签: python algorithm backtracking

我正在Python课程中做一些练习,其中一个我遇到的问题如下:

Given a digit sequence that represents a message where each uppercase letter 
is replaced with a number (A - 1, B - 2, ... , Z - 26) and space - 0. 
Find the number of the initial messages, from which that sequence 
could be obtained.

Example: 12345 - 3 (ABCDE, LCDE, AWDE)
         11 - 2 (AA, K)

天真的解决方案很简单,它是简单的强力算法:

import string

def count_init_messages(sequence):
    def get_alpha(seq):
        nonlocal count

        if len(seq) == 0:
            count += 1
            return

        for i in range(1, len(seq) + 1):
            if seq[:i] not in alph_table:
                break
            else:
                get_alpha(seq[i:])

    alphabet = " " + string.ascii_uppercase
    # generate dictionary of possible digit combination
    alph_table = {str(n): alph for n, alph in zip(range(len(alphabet)), alphabet)}
    # counter for the right combination met
    count = 0
    get_alpha(sequence)

    return count

def main():
    sequence = input().rstrip()
    print(count_init_messages2(sequence))

if __name__ == "__main__":
    main()

但是由于输入序列的长度可能长达100个字符并且可能有很多重复,因此我遇到了时间限制。例如,其中一个示例输入为2222222222222222222222222222222222222222222222222222222222222222222222 (possible messages number is 308061521170129)。由于我的实现过多重复,处理这样的输入需要很长时间。我想使用回溯算法,但我还没有意识到如何实现成功结果的记忆。

如果能够以正确的方式指出我如何打破这项任务,我会很高兴。

3 个答案:

答案 0 :(得分:4)

您必须解决的递归关系(s是一串数字,ab是个位数)是这样的:

 S("") = 1
 S(a) = 1
 S(s + a + b) = S(s+a) + (S(s) if ab is between 10 and 26)

可以使用动态编程而不是回溯来计算。如果你做得对,那就是O(n)时间复杂度,以及O(1)空间复杂度。

def seq(s):
    a1, a2 = 1, 1
    for i in xrange(1, len(s)):
        a1, a2 = a1 + (a2 if 9 < int(s[i-1:i+1]) < 27 else 0), a1
    return a1

print seq('2222222222222222222222222222222222222222222222222222222222222222222222')

答案 1 :(得分:0)

查找表中的最大数字是26,因此您永远不需要查找长度大于2的字符串。相应地修改for循环。这可能足以让蛮力生存。

答案 2 :(得分:0)

您可能还认可308061521170129为第71个斐波那契数字。这种关系与Fibonacci数字相对应,给出了某些枚举问题的解决方案。最常见的问题是计算总和为给定总数n的1和2的组合数:有Fn + 1种方法可以做到这一点&#34; (https://en.wikipedia.org/wiki/Fibonacci_number#Use_in_mathematics)。

字符串中可以分为单个或两个数字代码的每个连续子序列表示具有1和2的多个可能组合的n;因此,对于字符串中的每个这样的子序列,结果必须乘以(子序列长度+ 1)斐波那契数(在70 2&#39; s的情况下,我们只乘以1乘以71斐波那契数字。)