C#で二分木に指定した合計値となるパスが存在するか判定する方法
二分木において、ルートから葉までの経路(パス)上のノード値の合計が、指定された値と一致するかどうかを判定する問題は、木構造のアルゴリズム学習における定番テーマの一つです。この記事では、C#を使ってこの問題を再帰的に解く方法を解説します。
アルゴリズムの考え方
HasPathSum メソッドは、2つの引数を受け取ります。1つ目は木のノード、2つ目は目標となる合計値です。
処理の流れは以下のとおりです。
- 最初にノードが
nullかどうかをチェックします。ノードがnullの場合はfalseを返します。 - ノードが
nullでなければ、再帰メソッドhelperHasPathSumを呼び出します。 - 再帰の各ステップでは、現在のノードの値を合計値から引き算していきます。
- 葉ノード(左右の子を持たないノード)に到達した時点で合計値がちょうど 0 になっていれば、「指定された合計値に等しいパスが存在する」と判断し、
trueを返します。
このように「残りの合計値」を親から子へ渡しながら減算していくことで、各パスの合計が目標値と一致するかを効率的に判定できます。
実装例
public class TreesPgm{
public class Node{
public int Value;
public Node LeftChild;
public Node RightChild;
public Node(int value){
this.Value = value;
}
public override String ToString(){
return "Node=" + Value;
}
}
public bool HasPathSum(Node node, int sum){
if (node == null){
return false;
}
return helperHasPathSum(node, sum);
}
private bool helperHasPathSum(Node root, int sum){
if (root == null){
return false;
}
sum -= root.Value;
if (root.LeftChild == null && root.RightChild == null && sum == 0){
return true;
}
return helperHasPathSum(root.LeftChild, sum) || helperHasPathSum(root.RightChild, sum);
}
}
ポイントとして、公開メソッド HasPathSum で null チェックを行い、実際の再帰処理はプライベートメソッド helperHasPathSum に分離しています。これによりコードの責務が明確になり、可読性が向上します。また、葉ノードの判定を root.LeftChild == null && root.RightChild == null で行うことで、途中のノードで合計が 0 になっても誤って true を返さないようになっています。
入力例
5
2 6
1 3
7
出力結果
True
この例では、たとえば「5 → 2 → 3」というパスの合計が 10 になるため、指定した合計値に一致するパスが存在することになり、結果は True となります。
計算量について
このアルゴリズムは各ノードを一度だけ訪問するため、時間計算量は O(n)(n はノード数)です。また、再帰呼び出しの深さは木の高さに依存するため、空間計算量は最悪の場合 O(n)、バランスの取れた木では O(log n) となります。
-
Pythonで二分木の中から最大のBST(二分探索木)の合計値を見つけるプログラム
問題の概要ある二分木が与えられたとします。この木の部分木の中に二分探索木(BST)が存在するかどうかを調べ、その中で最も大きなBSTを見つけ出し、そのノード値の合計を求めるのが目的です。合計値は、そのBSTに含まれる各ノードの値をすべて足し合わせたものになります。例えば、入力が次のような二分木だったとしましょう。この場合、出力は 12 となります。与えられた二分木の中に存在するBSTは次の部分木です。このBSTのノード値の合計 = 12 となります。解き方のアプローチこの問題を解くために、以下の手順で処理を進めます。変数 c := 0、m := null、value := 0 を初期化します。
-
Pythonで解く二分木の最大パス和(Maximum Path Sum)
問題の概要空でない二分木が1つ与えられます。この木における「最大パス和」を求めるのが目的です。ここでいうパスとは、あるノードを起点として、親子関係で結ばれたノードをたどり任意のノードへ至るまでのノード列のことです。パスには少なくとも1つのノードが含まれている必要がありますが、必ずしも根(ルート)ノードを通る必要はありません。例として、次のような二分木が入力された場合を考えてみましょう。この場合の出力は 32 となります。アルゴリズムの考え方各ノードを「パスの折り返し地点」として捉えるのがポイントです。あるノードを頂点とするパスの和は、「左部分木からの最大寄与 + 右部分木からの最大寄与 + そ