Pythonでn個の異なるノードから生成できるBST(二分探索木)の数を求めるプログラム
整数 n が与えられたとします。[1, 2, ..., n] のような n 個の異なる値があるとき、これらの値を使って構成できるBST(二分探索木)の総数を数える必要があります。答えが非常に大きくなる可能性があるため、結果は 10^9+7 で割った余りとして返します。
たとえば、入力が n = 3 の場合、出力は 14 になります。

解法のアプローチ
この問題は、動的計画法(DP)を使って効率的に解くことができます。ある値を根に選ぶと、それより小さい値で作られる左部分木と、大きい値で作られる右部分木に分割できるため、小さな部分問題の答えを組み合わせることで全体の答えが求まります。
具体的には、次の手順に従います。
- a := [0, 1] で初期化されたリストを用意する
- m := 10^9+7(答えの剰余を取るための定数)
- max_n := 1000(事前計算しておく最大のノード数)
- k を 2 から max_n + 1 まで繰り返し、次の処理を行う
- a の末尾に (1 + Σ a[i] × a[k−i](i は 1 以上 k 未満のすべての値)) mod m を追加する
- (a[n + 1] − 1) mod m を答えとして返す
実装例
理解を深めるために、以下のPythonコードを見てみましょう。
def solve(n):
a = [0, 1]
m = 10**9+7
max_n = 1000
for k in range(2, max_n + 2):
a.append((1 + sum(a[i] * a[k - i] for i in range(1, k))) % m)
return ((a[n + 1] - 1) % m)
n = 3
print(solve(n))
入力
3
出力
14
このように、漸化式を用いた動的計画法によって、n 個の異なるノードから構成できるBSTの数を効率よく求めることができます。あらかじめ max_n まで計算しておくことで、複数のクエリにも高速に対応できる点もポイントです。
-
Pythonで同じラベルを持つサブツリー内のノード数を求めるプログラム
ここでは、n個のノードからなる根付きの一般木を考えます。ノードには0からn-1までの番号が振られており、各ノードには小文字の英字ラベルが割り当てられています。ラベルは配列labelsとして与えられ(labels[i]がi番目のノードのラベル)、木は辺リストで表現されます。各辺eは[u, v]という形式で、uが親、vが子であることを意味します。 求めたいのは、サイズnの配列Aです。A[i]には「i番目のノードと同じラベルを持つ、そのサブツリー内のノードの総数」を格納します。 例えば、入力が次のような場合を考えてみましょう。 n = 5、label = ccaca のとき、出力は [3, 2,
-
Pythonで二分探索木(BST)の指定範囲内にあるノード数を求める方法
問題の概要 二分探索木(BST)が与えられ、さらに左側の境界値 l と右側の境界値 r が指定されます。このとき、木に含まれるすべてのノードの中で、値が l 以上 r 以下の範囲内にあるノードの個数を求めるのが目的です。 例えば、次のような木が与えられたとします。 このとき l = 7、r = 13 とすると、範囲内に含まれるノードは 8、10、12 の3つなので、出力は 3 になります。 アルゴリズムの考え方 スタックを使った反復的な深さ優先探索(DFS)で木をたどります。重要なポイントは、二分探索木の性質を活かして枝刈り(pruning)を行うことです。値が境界より小さいノードの左側の