Pythonで原点から目的地までの移動経路のうち、辞書順でk番目に小さい文字列を求めるプログラム
問題概要
二次元平面上の原点 (0, 0) にいる状態から、1単位ずつの水平移動(H)と垂直移動(V)のみを使って点 (x, y) へ移動することを考えます。目的地への到達方法は複数存在し、それぞれの経路は「H」と「V」の列で表現できます。たとえば、(0, 0) から (2, 2) へ移動する場合、「HVVH」は有効な経路の一つです。
ここで整数 k が与えられたとき、すべての経路を辞書順に並べた際の k 番目の経路(文字列)を求めます。
たとえば、入力が (x, y) = (3, 3)、k = 3 の場合、出力は「HHVVVH」になります。
解法の考え方
この問題は、各ステップで「次に H を選んだ場合に作れる経路の総数」を数えながら、答えとなる文字列を1文字ずつ確定させていく貪欲法で解くことができます。
まず、現在位置 (p, q) から目的地 (x, y) までの総経路数を返す関数 paths() を定義します。残りの移動は H が (x − p) 回、V が (y − q) 回なので、その並べ方の総数は二項係数 C(x + y, x) = (x + y)! / (x! × y!) で求められます。min(x, y) < 0 の場合は経路が存在しないため 0 を返します。
あとは次の手順で経路を構築していきます。
- 結果を格納するリスト res を用意し、現在位置を (p, q) = (0, 0) に初期化します。
- (p, q) が (x, y) と一致するまで、次を繰り返します。
- n := paths(x − p − 1, y − q) … 次に H を選んだ場合の残りの経路数
- p + 1 ≤ x かつ k < n ならば、「H」を res の末尾に追加し、p を 1 増やします(先頭が H になる経路は全部で n 個あるため、k がその範囲内なら答えは H で始まります)
- そうでなければ、k := k − n として「V」を res の末尾に追加し、q を 1 増やします。
- 最後に res を連結した文字列を返します。
実装例
以下に Python での実装例を示します。
from math import factorial
def paths(x, y):
if min(x, y) < 0:
return 0
return factorial(x+y) / factorial(x) / factorial(y)
def solve(x, y, k):
res = []
p, q = 0, 0
while (p, q) != (x, y):
n = paths(x - p - 1, y - q)
if p + 1 <= x and k < n:
res.append('H')
p += 1
else:
k -= n
res.append('V')
q += 1
return ''.join(res)
(x, y) = (3, 3)
k = 3
print(solve(x, y, k))入力
(3, 3), 3
出力
HHVVVH
補足:より堅牢な実装について
上記のコードでは除算に「/」(浮動小数点除算)を使用しているため、x や y が大きくなると階乗の値が巨大になり、精度の低下が発生する可能性があります。Python 3.8 以降では math.comb(n, r) を使うことで、誤差のない正確な整数演算で二項係数を求められます。
from math import comb
def paths(x, y):
if min(x, y) < 0:
return 0
return comb(x + y, x)また、solve() 内で毎回 paths() を呼び出す代わりに、必要な二項係数を事前に計算しておく、あるいは動的計画法(DP)で経路数のテーブルを作成しておくことで、大きな入力に対しても高速かつ安定に動作させることができます。
-
Pythonで二分木の葉から始まる辞書順最小の文字列を求める方法
問題概要二分木のルートノードが与えられます。各ノードには0から25までの値が格納されており、これらは文字「a」から「z」に対応しています。つまり、0は「a」、1は「b」というように対応付けられています。このとき、木の葉から始まってルートで終わるパスの中で、辞書順(lexicographical order)で最も小さい文字列を見つける必要があります。例えば、次のような木を考えてみましょう。この場合、パスの値の並びは [0, 3, 25] となるため、出力は adz になります。解法のアプローチこの問題はDFS(深さ優先探索)を使って解くことができます。以下の手順で進めます。DFS走査用のメソッ
-
Pythonでリスト内の最小値を見つける方法を解説
この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。