Pythonで指定された制約のもと、別の文字列から目的の文字列を生成できるか判定する方法
問題の概要
小文字のみで構成される2つの文字列 s と t が与えられたとします。このとき、次の制約条件に従って t を s から生成できるかどうかを判定するのが本記事の目的です。
制約条件
- 文字の一致:
tに含まれる各文字は、sにも同じ個数だけ存在しなければなりません。たとえば、tに「a」が2つ含まれているなら、sにも「a」が2つ必要です。 - 前の文字による代替:
tのある文字がsに存在しない場合は、その直前の2つの文字(ASCIIコードで1つ前と2つ前の文字)がsに存在するかを確認します。たとえば、「f」がtにはあるがsにはない場合、「d」と「e」を組み合わせて「f」を作ることができます。
たとえば、入力が s = "pghn"、t = "pin" の場合を考えてみましょう。「i」は s に直接存在しませんが、「g」と「h」を組み合わせて「i」を作ることができるため、出力は True になります。
解決のためのアルゴリズム
この問題は、文字の出現頻度を管理しながら順番に処理することで解決できます。手順は以下の通りです。
freqとして、s内の各文字の出現回数を記録します。iを 0 からtの長さまで繰り返します。freq[t[i]]が 0 以外の場合:freq[t[i]]を 1 減らします。- それ以外で、
t[i]の1つ前の文字と2つ前の文字がどちらもfreqに残っている場合:両方のカウントをそれぞれ 1 ずつ減らします。 - 上記のいずれも満たさない場合:
Falseを返します。
- ループが最後まで完了すれば
Trueを返します。
Pythonでの実装例
以下のコードでは、collections.defaultdict を使って文字頻度を効率的に管理しています。存在しないキーにアクセスしてもエラーにならず、デフォルト値 0 が返されるため、コードがシンプルになります。
from collections import defaultdict
def solve(s, t):
freq = defaultdict(lambda: 0)
# 文字列sの各文字の出現回数をカウント
for i in range(0, len(s)):
freq[s[i]] += 1
# 文字列tの各文字について判定
for i in range(0, len(t)):
if freq[t[i]]:
freq[t[i]] -= 1
elif (freq[chr(ord(t[i]) - 1)] and freq[chr(ord(t[i]) - 2)]):
freq[chr(ord(t[i]) - 1)] -= 1
freq[chr(ord(t[i]) - 2)] -= 1
else:
return False
return True
s = "pghn"
t = "pin"
print(solve(s, t))入力
"pghn", "pin"
出力
True
処理のポイント
ord()関数で文字をASCIIコード(整数)に変換し、1つ前・2つ前の文字を求めた後、chr()で再び文字に戻しています。defaultdict(lambda: 0)を使うことで、未登録の文字に対する参照でも安全に 0 が返され、条件分岐が簡潔になります。- 計算量は文字列の長さに比例する O(n + m)(n は
sの長さ、m はtの長さ)となり、非常に効率的です。
-
Pythonでリスト内の文字列を連結して指定した文字列が作成できるか判定する方法
プログラミングでは、リストに含まれる複数の文字列を組み合わせて、目的の文字列が作成できるかどうかを確認したい場面があります。このとき、リスト内の文字列をどのような順序で連結してもよいという条件が付くことがあります。本記事では、Pythonを使ってこの問題を解決する2つの方法、「順列(permutations)」を使う方法と「正規表現」を使う方法について、具体的なコード例とともに解説します。方法1:itertoolsのpermutationsを使う標準ライブラリのitertoolsモジュールには、順列を生成するpermutations関数が用意されています。この関数を使うと、リスト内の文字列をさ
-
Pythonで文字列を別の文字列に追加(連結)する2つの方法
Pythonにおいて「文字列を追加する」というのは、複数の文字列をつなぎ合わせて新しい文字列を作ること(連結)を意味します。テキスト解析など、さまざまな場面で活用される基本的な操作です。この記事では、ある文字列を別の文字列に追加するための代表的な2つの方法を、サンプルコードと実行結果とともに解説します。方法1:+= 演算子を使う+ 演算子は、数値に対して使う場合と同じように文字列にも使用できます。ただし、文字列の場合は数値の加算ではなく連結が行われる点が異なります。コード例s1 = What a beautiful s2 = flower print(与えられた文字列 s1 :, s1)