回文数の問題を解決するための動的計画法と中心拡散法(Pythonで実装)

問題

  この質問は中程度の難易度の問題ですが、記録する価値のあるさまざまな方法があります。質問は次のとおりです。

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

  以下に、ブルートフォースソリューション、中央拡散、動的計画法の3つの方法を示します。

回答

暴力的な解決策

  最初に頭に浮かぶのは、文字列の最初の長さが1であることを覚えて、左から右にトラバースする、頭の悪い暴力的な解決策です。トラバーサルがパリンドロームの部分文字列を見つけると、文字列の長さが1増加し、長さが見つからなくなるまで増加します。palindromeサブストリング。この方法は簡単に思いつくことができますが、トラバーサルにより、時間の複雑さが増し、計算時間も長くなります。

  回文部分文字列であるかどうかを判断するには、次の2つの方法があります。

  1. 文字列の長さnは奇数で、0からn − 1 2 \ frac {n-1} {2}2N - 1そしてn + 1 2 \ frac {n + 1} {2}2N + 1 nへの部分文字列は逆の関係であり、回文数文字列であるかどうかを確認するために判断する必要があるだけです。

  2. 文字列の長さnは偶数であり、文字列を2つの等間隔のセグメントに分割し、それが逆の関係であるかどうかを判断します。

    コードは次のとおりです。

 def judge_Palindrome(s):
     if len(s) % 2 == 1:   # odd
         if s[0:int(len(s) / 2)] == s[:int(len(s) / 2):-1]:
             return True
         else:
             return False
     elif len(s) % 2 == 0:   # even
         if s[0:int(len(s) / 2)] == s[-1:-int(len(s) / 2) - 1:-1]:
             return True
         else:
             return False

  次のアイデアは最初に述べたものと同じですが、トラバースするだけです。

if len(s) < 2:
    l = s
else:
    l = s[0]
    i = 2
    while i <= len(s):
        for start_node in range(0, len(s) - i + 1):
            if judge_Palindrome(s[start_node:start_node + i]):
                l_longest = i
                l = s[start_node:start_node + i]
                break
            else :
                continue
        i = i + 1

センタースプレッド

  また、各要素を中心として左から右に移動し、満足できる最長の回文の終わりまで左右に広がります。

def center_spread(s, size, left, right):
    i = left
    j = right
    
    while i >= 0 and j < size and s[i] == s[j]:
        i -= 1
        j += 1
    return s[i + 1:j], j - i - 1    

if len(s) < 2:
    l = s
else :
    max_len = 1
    l = s[0]
    
    for i in range(len(s)):
        l_odd, odd_len = center_spread(s, len(s), i, i)
        l_even, even_len = center_spread(s, len(s), i, i + 1)
        # find the current maximum length
        cur_max_l = l_odd if odd_len > even_len else l_even
        if len(cur_max_l) > max_len:
            max_len = len(cur_max_l)
            l = cur_max_l

動的計画法

  2つの重要なポイントがあります。

  1. 「状態」を定義する

    dp [l] [r] dp [l] [r] d p [ l ] [ r ]は、部分文字列s [l、r] s [l、r]を表します。s [ l r ](区間の左端と右端を含む)が回文文字列を構成するかどうかは、2次元のブール配列です。つまり、部分文字列s [l、r] s [l、r]の場合s [ l r ]は回文であり、dp [l] [r] = T rue dp [l] [r] = Trued p [ l ] [ r ]=T R U E

  2. 「状態遷移方程式」を見つける

dp[l, r] = (s[l] == s[r] and (r - l <= 2 or dp[l + 1, r - 1]))

S [L、R]の[L、R]s [ l r ]がテキスト文字列の場合、間違いなく、s [l + 1、r − 1] s [l + 1、r-1]s [ l+1 r1 ]もテキスト文字列です。注意すべきことは、s [l + 1、r − 1] s [l + 1、r-1]の場合だけです。s [ l+1 r1 ]要素が1つしかない場合、または要素がない場合、dpで判断することはできませんが、s [l] = s [r] s [l] = s [r]であるため、現時点ではテキスト文字列である必要がありますs [ l ]=s [ r ]

コードを以下に示します。

size = len(s)
if size < 2:
    res = s
else :
    dp = [[False for _ in range(size)] for _ in range(size)]
    longest_l = 1
    res = s[0]
    for r in range(1, size):
        for l in range(size):
            if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
                dp[l][r] = True
                cur_len = r - l + 1
                if cur_len > longest_l:
                    longest_l = cur_len
                    res = s[l:r + 1]

− − − − − − − − − − − − − − − − ---------------- - -
この記事は、最初に登場しzyairelu.cn
コメントに私のウェブサイトへようこそと話し合う
個人的なメールボックス[email protected]
- - - - - - - - - - - - - - - - -------- - -------

おすすめ

転載: blog.csdn.net/weixin_42731543/article/details/102767373