簡體   English   中英

如何應用回溯算法?

[英]How to apply a backtracking algorithm?

我正在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) 由於我的實現過多重復,處理這樣的輸入需要很長時間。 我想使用回溯算法,但我還沒有意識到如何實現成功結果的memoization。

如果能夠以正確的方式指出我如何打破這項任務,我會很高興的。

你必須解決的遞歸關系(其中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')

查找表中的最大數字是26,因此您永遠不需要查找長度大於2的字符串。相應地修改for循環。 這可能足以使蠻力可行。

您可能還認可308061521170129為第71個斐波那契數字。 這種關系與Fibonacci數字相對應,給出了“某些枚舉問題的解決方案。最常見的問題是計算總和為n的1和2的組合數:有Fn + 1種方法可以做到這一點“( https://en.wikipedia.org/wiki/Fibonacci_number#Use_in_mathematics )。

字符串中可以分成單個或雙個數字代碼的每個連續子序列表示具有1和2的多個可能組合的n ; 因此,對於字符串中的每個這樣的子序列,結果必須乘以(子序列的長度+ 1)斐波納契數(在70 2的情況下,我們只乘以第71個斐波納契數)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM