Pythonで最大k文字の削除により回文を作れるかどうかを判定するプログラム
文字列 s が与えられたとき、最大 k 文字を削除することでその文字列を回文(前から読んでも後ろから読んでも同じになる文字列)にできるかどうかを判定する問題を考えてみましょう。
例えば、s = "lieuvrel"、k = 4 という入力の場合、出力は True になります。3 文字を削除すれば回文 "level" を作ることができるためです。
解法のアプローチ:最長共通部分列(LCS)を活用する
この問題は、最長共通部分列(LCS:Longest Common Subsequence)を利用すると効率的に解けます。考え方のポイントは以下の通りです。
- 文字列 s と、それを逆順にした文字列との最長共通部分列の長さを求めます。
- 「元の文字列の長さ − LCS の長さ」が、回文にするために削除が必要な最小文字数に相当します。
- この値が k 以下であれば、最大 k 文字の削除で回文を作ることができます。
アルゴリズムの手順
まず、2 つの文字列 a, b を受け取る関数 lcs() を次のように定義します。
- m := a の長さ、n := b の長さとする
- (m + 1) × (n + 1) のサイズの表 table を用意し、すべて 0 で初期化する
- i を 1 から m まで繰り返しながら、j を 1 から n まで繰り返す:
・a[i - 1] と b[j - 1] が一致する場合:table[i][j] := 1 + table[i - 1][j - 1]
・一致しない場合:table[i][j] := max(table[i][j - 1], table[i - 1][j]) - table[m][n] を返す
メイン処理では、「len(s) − lcs(s, s の逆順) ≤ k」が成り立てば True を、そうでなければ False を返します。
実装例
それでは、実際のコードを見て理解を深めましょう。
class Solution: def solve(self, s, k): def lcs(a, b): m, n = len(a), len(b) table = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if a[i - 1] == b[j - 1]: table[i][j] = 1 + table[i - 1][j - 1] else: table[i][j] = max(table[i][j - 1], table[i - 1][j]) return table[m][n] return len(s) - lcs(s, s[::-1]) <= k ob = Solution() s = "lieuvrel" k = 4 print(ob.solve(s, k))
入力
"lieuvrel", 4
出力
True
計算量について
このアルゴリズムの時間計算量は O(m × n)、空間計算量も O(m × n) です(m, n はそれぞれ文字列の長さ)。動的計画法によって各部分問題を一度だけ計算するため、全ての削除パターンを総当たりする方法よりも大幅に効率的になっています。
-
Pythonで左右の部分木の入れ替えにより2つの二分木を一致させられるか判定する方法
問題の概要 2つの二分木が与えられたとき、任意のノードについて左部分木と右部分木を何度でも入れ替えてよいと仮定します。この操作を繰り返すことで、1つ目の木を2つ目の木とまったく同じ形に変換できるかどうかを判定するのが、この記事で扱う問題です。 例えば、次のような2つの木が入力として与えられた場合、左右の入れ替えによって一致させられるため、出力は True になります。 解決のアプローチ この問題は、幅優先探索(BFS)の考え方を使い、木をレベル(深さ)ごとに処理しながらノードの値を比較することで解けます。左右の入れ替えによって同じレベル内の値の並び順は反転し得るため、「順方向」または「逆方
-
Pythonで二分木の通り順走査(Inorder Traversal)が回文かどうかを判定する方法
問題の概要各ノードに0〜9のいずれかの数字が格納された二分木があるとします。この木を通り順走査(inorder traversal)した結果が回文(前から読んでも後ろから読んでも同じ並び)になっているかどうかを判定するプログラムを作成します。例えば、次のような木が入力として与えられた場合を考えてみましょう。この木の通り順走査の結果は [2, 6, 10, 6, 2] となり、左右対称の並びであるため、出力は True になります。解決のアプローチこの問題は、再帰を使わずにスタックを利用した反復的な通り順走査を行うことで解けます。手順は以下のとおりです。ルートが null の場合は True を