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

Pythonで最小の長さ差となる等しい部分文字列ペアの個数を求める方法

問題の概要

小文字アルファベットのみで構成された2つの文字列が与えられます。このとき、次の条件をすべて満たす四つ組 (p, q, r, s) の個数を求めることを考えます。

  • 0 <= p <= q <= 1つ目の文字列の長さ
  • 0 <= r <= s <= 2つ目の文字列の長さ
  • 1つ目の文字列のインデックス p〜q にある部分文字列と、2つ目の文字列のインデックス r〜s にある部分文字列が完全に一致する
  • 上記の条件を満たすすべての四つ組の中で、q − r の値が最小である

たとえば、firstString = 'hgfn'、secondString = 'gfrt' という入力に対する出力は 2 になります。実際、(1, 1, 0, 0) と (2, 2, 1, 1) の2つの四つ組が条件を満たしており、どちらも q − r の値が最小(1)になっています。

アプローチ:各文字の出現位置に注目する

この問題を素朴に全探索すると計算量が膨大になりますが、「最適な四つ組では部分文字列の長さが必ず1文字になる」という性質に着目すれば、非常にシンプルに解けます。

部分文字列をそれ以上伸ばしても、q − r の値が小さくなることはないためです。したがって、両方の文字列に共通して現れる各文字 c について、次の2点だけを考えれば十分です。

  • 1つ目の文字列における c の最初の出現位置(インデックス p)
  • 2つ目の文字列における c の最後の出現位置(インデックス r)

このとき q = p、s = r として q − r = p − r を計算し、共通するすべての文字の中でこの値が最小となるものを探します。そして、その最小値に一致する文字の個数こそが答えとなります。

アルゴリズムの手順

  1. サイズ26の配列 left を無限大で初期化し、1つ目の文字列を走査しながら各文字(a〜z)の最初の出現位置を記録します。
  2. サイズ26の配列 right を -1 で初期化し、2つ目の文字列を走査しながら各文字の最後の出現位置を記録します。
  3. left[c] が有効な値(無限大以外)である各文字について、left[c] − right[c] を計算し、その最小値 mi を求めます。
  4. left[c] と right[c] がどちらも有効で、かつ left[c] − right[c] == mi となる文字の個数を数えます。これが最終的な答えです。

Pythonでの実装例

それでは、上記の手順を実際のコードで確認してみましょう。

def solve(firstString, secondString):
    left = [float('inf')] * 26
    right = [-1] * 26
    res = 0
    mi = float('inf')

    for i, ch in enumerate(firstString):
        left[ord(ch) - ord('a')] = min(left[ord(ch) - ord('a')], i)

    for i, ch in enumerate(secondString):
        right[ord(ch) - ord('a')] = max(right[ord(ch) - ord('a')], i)

    for i in range(26):
        if left[i] != float('inf'):
            mi = min(mi, left[i] - right[i])

    for i in range(26):
        if left[i] != float('inf') and right[i] != -1:
            if left[i] - right[i] == mi:
                res += 1

    return res

print(solve('hgfn', 'gfrt'))

実行結果

入力

'hgfn', 'gfrt'

出力

2

計算量の評価

このアルゴリズムの時間計算量は O(n + m)(n、m はそれぞれ2つの文字列の長さ)です。各文字列を一度ずつ走査し、その後にサイズ26の配列を2回確認するだけだからです。また、使用するのはサイズ26の固定配列のみなので、空間計算量は O(1) となります。

  1. Pythonで倉庫(godown)に押し込めるボックスの数を求めるプログラム

    問題の概要 2つの整数配列が与えられていると仮定しましょう。一方のリストには単位幅のボックスの高さが、もう一方の配列には倉庫(godown)内の各部屋の高さが格納されています。部屋には 0〜n の番号が付いており、各部屋の高さは godown 配列の対応するインデックスに記録されています。ここで、倉庫に押し込むことのできるボックスの数を求めます。 ただし、以下のルールを守る必要があります。 ボックスを積み重ねることはできません。 ボックスの順序は自由に入れ替えられます。 ボックスは必ず左から右へ向かって挿入します。 もしボックスの高さがある部屋の高さより大きい場合、そのボックスおよびそれよ

  2. Pythonでリスト内の最小値を見つける方法を解説

    この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。