Pythonでグリッド内に指定した単語が存在するか確認する方法
文字が敷き詰められたグリッド(2次元のマトリックス)が与えられ、その中に指定した単語が存在するかどうかを確認する問題を考えてみましょう。単語は4つの方向、すなわち水平方向の左・右、垂直方向の上・下に沿って読める場合に「存在する」とみなします。見つかれば True を、見つからなければ False を返します。
たとえば、次のようなグリッドが与えられたとします。
| p | g | h | s | f |
| y | k | d | g | h |
| t | k | g | h | i |
| h | n | s | j | s |
| o | j | f | g | h |
| n | r | t | y | u |
この状態で input_str = 'python' を探すと、1列目を上から下へ p → y → t → h → o → n とたどることで単語が見つかるため、出力は True になります。
アルゴリズムの流れ
この問題は、深さ優先探索(DFS)とバックトラッキングを組み合わせて解くのが定番です。手順は以下の通りです。
- 関数
find_grid()を定義します。引数は matrix(グリッド)、input_str(探す単語)、row_pos(現在の行位置)、col_pos(現在の列位置)、row_count(行数)、col_count(列数)、degree(ここまでに一致した文字数)です。- degree が input_str の長さと等しい場合:すべての文字を一致させられたので
Trueを返します。 - row_pos または col_pos がグリッドの範囲外の場合:
Falseを返します。 - matrix[row_pos][col_pos] が input_str[degree] と一致する場合:
- 現在の文字を一時変数 temp に保存し、そのセルを「#」に置き換えて、同じセルを二度使わないようにします。
- 上下左右の4方向に対して find_grid() を再帰呼び出しし、その結果を論理和(OR)で結合します。
- 探索後、セルを temp の値に戻して(バックトラッキング)、result を返します。
- それ以外の場合:
Falseを返します。
- degree が input_str の長さと等しい場合:すべての文字を一致させられたので
- メインの solve 関数では、まず input_str の長さが 行数 × 列数 を超えていれば
Falseを返します。 - グリッド全体を走査し、matrix[row][col] が input_str[0](先頭文字)と一致するセルを起点として find_grid() を呼び出します。結果が
TrueならTrueを返します。 - どこから始めても見つからなければ
Falseを返します。
実装例
理解を深めるために、実際のPythonコードを見てみましょう。
def find_grid(matrix, input_str, row_pos, col_pos, row_count, col_count, degree):
if degree == len(input_str):
return True
if row_pos < 0 or col_pos < 0 or row_pos >= row_count or col_pos >= col_count:
return False
if matrix[row_pos][col_pos] == input_str[degree]:
temp = matrix[row_pos][col_pos]
# 同じセルを再訪しないよう、一時的に「#」でマークする
matrix[row_pos] = matrix[row_pos][:col_pos] + '#' + matrix[row_pos][col_pos + 1:]
result = (find_grid(matrix, input_str, row_pos - 1, col_pos, row_count, col_count, degree + 1) |
find_grid(matrix, input_str, row_pos + 1, col_pos, row_count, col_count, degree + 1) |
find_grid(matrix, input_str, row_pos, col_pos - 1, row_count, col_count, degree + 1) |
find_grid(matrix, input_str, row_pos, col_pos + 1, row_count, col_count, degree + 1))
# バックトラッキング:セルを元の文字に戻す
matrix[row_pos] = matrix[row_pos][:col_pos] + temp + matrix[row_pos][col_pos + 1:]
return result
else:
return False
def solve(matrix, input_str, row_count, col_count):
if len(input_str) > row_count * col_count:
return False
for row in range(row_count):
for col in range(col_count):
if matrix[row][col] == input_str[0]:
if find_grid(matrix, input_str, row, col, row_count, col_count, 0):
return True
return False
word_grid = ['pghsf', 'ykdgh', 'tkghi', 'hnsjs', 'ojfgh', 'nrtyu']
print(solve(word_grid, 'python', 6, 5))
入力
['pghsf', 'ykdgh', 'tkghi', 'hnsjs', 'ojfgh', 'nrtyu'], 'python'
出力
True
計算量と実装のポイント
各セルを起点に最大4方向へ再帰探索が広がるため、時間計算量は O(R × C × 4L)(R:行数、C:列数、L:単語の長さ)となります。重要なのは、訪問済みのセルを一時的に「#」でマークし、再帰から戻るときに必ず元の文字へ復元するバックトラッキングの処理です。これにより、別の開始セルからの探索が常にクリーンな状態で行えるようになります。なお、Pythonの文字列はイミュータブル(変更不可)なので、セルのマークと復元にはスライスを使って新しい文字列を作り直す点にも注意してください。
-
Pythonで数値が二面素数(Dihedral Prime)かどうかを判定する方法
ある整数nが与えられたとき、それが「二面素数(dihedral prime)」であるかどうかを判定する方法を解説します。二面素数とは、その数自体が素数であり、さらに7セグメントディスプレイに表示した際に、表示の向き(通常の向きでも上下逆さまでも)に関わらず、同じ数または別の素数として読み取れる数のことです。例えば、入力がn = 1181の場合、出力はTrueになります。下の数字は上の数字を上下逆さま(180度回転)にして表示したものであり、どちらも素数となっています。アルゴリズムの手順この問題を解くために、以下の手順で進めます。up_side_down() 関数を定義します。引数としてnを受け
-
Pythonで数独グリッドの有効性を検証するプログラムの実装方法
数独グリッドの有効性検証とは? ここでは、9×9の数独(スドク)グリッドが有効(valid)であるかどうかを判定するプログラムを扱います。検証の対象となるのは、すでに埋められているセルだけであり、次のルールに従ってチェックを行います。 行のルール:各行には、1〜9の数字が重複することなく含まれていること。 列のルール:各列にも、1〜9の数字が重複することなく含まれていること。 ブロックのルール:グリッド内の9つの3×3サブボックス(ブロック)のそれぞれにも、1〜9の数字が重複せずに含まれていること。 例として、次のような数独グリッドを考えてみます。 このグリッドは有効です。 解法のアプ