C++でノード値の合計が最小となる二分木のレベルを求めるプログラム
二分木(バイナリツリー)を考えます。根(ルート)のレベルを1とし、その子のレベルを2、さらにその下のレベルを3というように定義します。このとき、レベルXに存在するすべてのノードの値の合計が最小になるような、最も小さいレベルXを見つけるのが本記事の目的です。
例として、次のような二分木を考えてみましょう。

この場合、出力は 2 となります。なぜなら、レベル2のノードの値の合計は 4 + (-10) = -6 となり、これが全レベルの中で最小だからです。
解法のアプローチ
この問題は、幅優先探索(BFS)を使って各レベルごとにノードの値の合計を計算し、その中で最小となるレベルを記録していくことで解けます。具体的には、以下の手順に従います。
level := 1、sum := ルートrの値、ansLevel := level、ansSum := sumで初期化する。- キュー
qを定義し、ルートノードrを挿入する。 - キュー
qが空でない間、以下を繰り返す。capacity := キューqのサイズを取得する。levelを1増やし、sum := 0にリセットする。capacityが0になるまで以下を繰り返す。- キューの先頭ノードを取り出し、キューから削除する。
- 右の子が存在する場合、
sumに右の子の値を加算し、右の子をキューに挿入する。 - 左の子が存在する場合、
sumに左の子の値を加算し、左の子をキューに挿入する。 capacityを1減らす。
ansSum > sumの場合、ansSum := sum、ansLevel := levelと更新する。
ansLevelを返す。
C++による実装例
それでは、実際の実装を見て理解を深めましょう。
#include <bits/stdc++.h>
using namespace std;
class TreeNode{
public:
int val;
TreeNode *left, *right;
TreeNode(int data){
val = data;
left = NULL;
right = NULL;
}
};
class Solution {
public:
int solve(TreeNode* r) {
int level = 1, sum = r->val;
int ansLevel = level, ansSum = sum;
queue <TreeNode*> q;
q.push(r);
while(!q.empty()){
int capacity = q.size();
level++;
sum = 0;
while(capacity--){
TreeNode* node = q.front();
q.pop();
if(node->right){
sum += node->right->val;
q.push(node->right);
}
if(node->left){
sum += node->left->val;
q.push(node->left);
}
}
if(ansSum>sum){
ansSum = sum;
ansLevel = level;
}
}
return ansLevel;
}
};
main(){
TreeNode *root = new TreeNode(5);
root->left = new TreeNode(4);
root->right = new TreeNode(-10);
root->left->right = new TreeNode(-2);
root->right->left = new TreeNode(-7);
root->right->right = new TreeNode(15);
Solution ob;
cout <<ob.solve(root);
}入力
TreeNode *root = new TreeNode(5); root->left = new TreeNode(4); root->right = new TreeNode(-10); root->left->right = new TreeNode(-2); root->right->left = new TreeNode(-7); root->right->right = new TreeNode(15);
出力
2
アルゴリズムのポイント
この実装では、キューの現在のサイズを capacity として保存することで、「同じレベルのノードだけを処理する」というBFSの重要な性質を実現しています。各レベルの処理が終わった時点で sum にはそのレベルのノード値の合計が入るため、これまでの最小値 ansSum と比較して、より小さい場合は ansLevel を更新します。
計算量についても触れておきましょう。すべてのノードをちょうど1回ずつ訪問するため、時間計算量はO(n)(nはノード数)、キューに格納されるノード数は最大で木の幅程度なので、空間計算量もO(n) となります。
-
C++で二分木における最大部分木の合計を求める方法
この問題では、二分木(バイナリツリー)が与えられます。私たちのタスクは、木の中で最も大きな合計値を持つ部分木を見つけることです。 問題の概要 二分木には正の値と負の値が混在しています。その中から、ノードの合計が最大になる部分木を特定する必要があります。 例で問題を理解しよう 出力: 13 説明: 左部分木の合計:7 右部分木の合計:1 木全体の合計:13 このように、根を含む木全体の合計である「13」が最大の部分木の合計となります。 解法のアプローチ この問題を解くためには、後順走査(ポストオーダー走査)を利用します。手順は以下の通りです。 左部分木と右部分木それぞれのノードの合計を再
-
C++で二分木の右側の葉(右葉)の合計を求める方法
二分木が与えられたとき、その木に含まれるすべての「右葉(右側につながった葉ノード)」の値の合計を求める問題を考えてみましょう。 例えば、次のような二分木が入力として与えられた場合を考えます。 この場合の出力は 17 になります。この二分木には値が 7 と 10 の2つの右葉が存在するためです。 解決のためのアプローチ この問題は、DFS(深さ優先探索)を利用することで効率的に解くことができます。手順は以下の通りです。 dfs() 関数を定義します。引数としてノード(node)とブール値のフラグ(add)を受け取ります。 node が null の場合は、何もせずに処理を終了して戻ります。