Pythonですべての母音を含み子音を含まない部分文字列を検索する方法
問題の概要
小文字のアルファベットのみで構成された文字列が与えられたとします。この文字列から、5つの母音(a、e、i、o、u)をすべて少なくとも1回ずつ含み、かつ子音を一切含まない部分文字列をすべて見つけ出すのが今回の課題です。
例えば、入力として "helloworldaeiouaiunicestring" が与えられた場合、出力は次の7つの部分文字列になります。
- aeiou
- aeioua
- aeiouai
- aeiouaiu
- eioua
- eiouai
- eiouaiu
これらはいずれも母音だけで構成されており、かつ a・e・i・o・u の5種類すべてが含まれている点に注目してください。
解決のためのアルゴリズム
この問題は、連続する母音のかたまり(ブロック)ごとに調べることで効率よく解けます。手順は以下の通りです。
- 文字列 s の長さを n とします。
- 開始位置 i を 0 から n-1 まで順に動かし、その都度以下を実行します。
- 出現した母音を記録するための空の辞書 my_map を用意します。
- 終了位置 j を i から n-1 まで順に動かします。
- s[j] が母音でなければ、そこでループを中断します(子音を含む部分文字列は対象外のため)。
- 母音であれば、my_map[s[j]] = 1 として出現を記録します。
- my_map のサイズ(= 出現した母音の種類数)が 5 になった時点で、s[i:j+1](i 番目から j 番目までの部分文字列)を出力します。
辞書のキー数が自動的に重複を除いた母音の種類数になるため、「5種類すべてが出現したか」の判定が非常にシンプルになります。
実装例
それでは、上記の手順をPythonで実装してみましょう。
def isVowel(x):
if x in ['a','e','i','o','u']:
return True
return False
def get_substrings(s):
n = len(s)
for i in range(n):
my_map = dict()
for j in range(i, n):
if (isVowel(s[j]) == False):
break
my_map[s[j]] = 1
if (len(my_map) == 5):
print(s[i:j + 1])
s = "helloworldaeiouaiunicestring"
get_substrings(s)入力
"helloworldaeiouaiunicestring"
出力
aeiou aeioua aeiouai aeiouaiu eioua eiouai eiouaiu
処理のポイント
- 早期終了: 子音を検出した時点で内側のループを break することで、無駄な探索を省いています。これにより、連続する母音ブロックごとに独立して判定できます。
- 辞書による重複管理: 辞書は同じキーに対して値を上書きするだけなので、母音の「種類数」を len(my_map) で即座に取得できます。set() を使っても同様の結果が得られます。
- 計算量: 最悪ケースでは O(n²) となりますが、各開始位置での探索は子音で打ち切られるため、実際のデータでは高速に動作します。
-
Pythonで全ての点を接続するための最小コストを求めるプログラム
問題の概要(x, y) の形式で表される複数の点が格納された配列 points があるとします。2つの点 (xi, yi) と (xj, yj) を接続するコストは、それらの間のマンハッタン距離として定義されます。マンハッタン距離は次の式で計算できます。|xi − xj| + |yi − yj|この問題では、すべての点を接続するために必要な最小のコストを求める必要があります。入力例points = [(0,0), (3,3), (2,10), (6,3), (8,0)]この場合、出力は 22 になります。これは、各辺の距離がそれぞれ 6 + 5 + 3 + 8 = 22 となるように点同士を接
-
Pythonで2次元行列内の0で埋められた長方形をすべて検出する方法
はじめに本記事では、0と1のみで構成される2次元のバイナリ行列が与えられたとき、0で埋められたすべての長方形の開始座標と終了座標を見つけるアルゴリズムをPythonで実装する方法を解説します。前提条件として、各長方形は互いに分離しており、接触しないものとします。ただし、配列(行列)の境界には接していても構いません。また、要素が1つだけの長方形も存在しえます。問題の例たとえば、以下のような入力行列を考えてみましょう。10111011101111101100110110011011011101000011100011011101この場合、出力は次のようになります。各リストは [開始行, 開始列,