Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで解く:文字列sから削除してもtが部分列であり続ける最大の部分文字列の長さを求める方法

文字列 s と、s の部分列(サブシーケンス)となっている別の文字列 t が与えられます。求めたいのは、削除した後も ts の部分列であり続けるような、削除可能な部分文字列の長さの最大値です。

たとえば、入力が s = "xyzxyxz"t = "yz" の場合、出力は 4 になります。先頭の4文字 "xyzx" を削除しても、残った文字列には依然として "yz" が部分列として含まれているためです。

解法のアプローチ

この問題は貪欲法(グリーディ法)を使うことで効率的に解けます。ポイントは、次の3つの候補を調べることです。

  • c1(末尾側の削除):左から貪欲に t をマッチングさせ、最後の文字が一致した位置より後ろをすべて削除できる長さ。
  • c2(先頭側の削除):右から貪欲に t をマッチングさせ、最初の文字が一致した位置より前をすべて削除できる長さ。
  • c3(中間の削除):左寄せのマッチング位置と右寄せのマッチング位置の間にあるギャップのうち、最大のもの。

具体的な手順

  1. 空のリスト leftright を用意し、c1 = c2 = c3 = -1j = 0 で初期化します。
  2. i を 0 から s の末尾まで順に走査します。s[i]t[j] と一致したら、ileft の末尾に追加して j を1増やします。jt の長さに達したら、c1 = len(s) - i - 1 としてループを抜けます。
  3. 次に j = len(t) - 1 とし、is の末尾から先頭へ向かって走査します。s[i]t[j] と一致したら、iright の先頭に挿入して j を1減らします。j が -1 になったら、c2 = i としてループを抜けます。
  4. i を 0 から len(t) - 2 まで走査し、c3 = max(c3, right[i + 1] - left[i] - 1) を計算します。
  5. 最後に c1c2c3 の最大値を返します。

Pythonでの実装例

理解を深めるために、以下の実装を見てみましょう。

class Solution:
   def solve(self, s, t):
      left = []
      right = []
      c1 = -1
      c2 = -1
      c3 = -1
      j = 0
      for i in range(len(s)):
         if s[i] == t[j]:
            left.append(i)
            j += 1
         if j == len(t):
            c1 = len(s) - i - 1
            break
      j = len(t) - 1
      for i in range(len(s) - 1, -1, -1):
         if s[i] == t[j]:
            right.insert(0, i)
            j -= 1
         if j == -1:
            c2 = i
            break
      for i in range(len(t) - 1):
         c3 = max(c3, right[i + 1] - left[i] - 1)
      return max(c1, c2, c3)
ob = Solution()
s = "xyzxyxz"
t = "yz"
print(ob.solve(s, t))

入力

"xyzxyxz", "yz"

出力

4

このアルゴリズムの計算量は O(n) であり、文字列を数回走査するだけで答えが求まるため、非常に効率的です。部分列のマッチング問題において、貪欲に左端・右端を固定して中間の余白を最大化するという発想は、他の文字列処理の問題にも応用できます。

  1. Pythonで最長のバランス括弧部分列の長さを求めるプログラム

    問題概要 文字列 s が与えられます。この文字列には括弧「(」と「)」が含まれており、その中からバランスの取れた(対応関係が成立している)括弧の部分列として最も長いものを見つけ、その長さを返すことが目標です。 たとえば、入力が s = ())(()( の場合、出力は 4 になります。「(」と「)」を選び抜いて ()() というバランスの取れた部分列を作れるためです。 解法のアプローチ この問題は、文字列を後ろから走査することで線形時間で解けます。閉じ括弧を先に確保しておき、開き括弧が出てきたときに対を成立させるという発想です。手順は以下の通りです。 結果を格納する変数 res を 0 で初

  2. Pythonで指定した文字を使って作成できる最長単語の長さを求めるプログラム

    文字列のリスト words と、別の文字列 letters が与えられたとします。このとき、letters に含まれる文字だけを使って作成できる words 内の最も長い文字列の長さを求めます。どの単語も作成できない場合は 0 を返します。なお、同じ文字を再利用することはできません。例として、words = [dog, cat, rat, bunny, lion, bat]、letters = gabctnyu の場合を考えてみましょう。このとき出力は 3 になります。「cat」や「bat」なら与えられた文字で作成できますが、それより長い単語は作れないため、最大の長さは 3 となるからです。解