C++で二分木の最大レベル合計を求めるアルゴリズム
問題概要
二分木(バイナリツリー)のルートノードが与えられたとき、ルートのレベルを1とし、その子ノードをレベル2、さらにその下をレベル3として数えていきます。このとき、「全ノードの値の合計が最大になる最小のレベルX」を求めて返すのが本問題の目的です。
例えば、次のような二分木を考えてみましょう。

この場合の出力は「2」となります。各レベルの合計を計算すると以下のようになります。
- レベル1の合計:1
- レベル2の合計:7 + 0 = 7
- レベル3の合計:7 + (-8) = -1
最大の合計はレベル2の「7」であるため、答えは2になります。
解法のアプローチ
この問題は、幅優先探索(BFS)を使って各レベルごとのノードの値を合計し、その中で最大となるレベルを記録していくことで解けます。具体的な手順は以下の通りです。
- 初期化: level := 1、sum := ルートrの値、ansLevel := level、ansSum := sum と設定します。
- キューの準備: キューqを定義し、ルートノードrを挿入します。
- ループ処理: qが空でない間、以下を繰り返します。
- capacity := qのサイズを取得します。
- levelを1増やし、sum := 0にリセットします。
- capacityが0になるまで、以下を繰り返します。
- node := qの先頭ノードを取り出し、キューから削除します。
- 右の子ノードが存在する場合は、sumにその値を加算し、右の子ノードをqに挿入します。
- 左の子ノードが存在する場合は、sumにその値を加算し、左の子ノードをqに挿入します。
- capacityを1減らします。
- ansSum < sum であれば、ansSum := sum、ansLevel := level を更新します。
- 結果の返却: ansLevelを返します。
C++での実装例
それでは、実際の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;
}
};
void insert(TreeNode **root, int val){
queue<TreeNode*> q;
q.push(*root);
while(q.size()){
TreeNode *temp = q.front();
q.pop();
if(!temp->left){
if(val != NULL)
temp->left = new TreeNode(val);
else
temp->left = new TreeNode(0);
return;
}
else{
q.push(temp->left);
}
if(!temp->right){
if(val != NULL)
temp->right = new TreeNode(val);
else
temp->right = new TreeNode(0);
return;
}
else{
q.push(temp->right);
}
}
}
TreeNode *make_tree(vector<int> v){
TreeNode *root = new TreeNode(v[0]);
for(int i = 1; i<v.size(); i++){
insert(&root, v[i]);
}
return root;
}
class Solution {
public:
int maxLevelSum(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(){
vector<int> v = {1,7,0,7,-8,NULL,NULL};
TreeNode *root = make_tree(v);
Solution ob;
cout <<ob.maxLevelSum(root);
}入力例
[1,7,0,7,-8,null,null]
出力例
2
計算量について
このアルゴリズムの時間計算量はO(N)です。Nは二分木内のノード総数であり、各ノードを一度だけ訪問するためです。空間計算量もO(N)となり、BFSに使用するキューが最悪の場合、1レベルあたりのノード数分のメモリを保持する必要があるためです。
-
C++で二分木がレベルごとにソートされているかを確認する方法
本記事では、二分木(バイナリツリー)がレベルごとにソートされているかどうかを判定する方法を解説します。レベルごとにソートされた二分木とは、以下のような構造を持つ木のことです。このような二分木では、各レベル内でノードが左から右へ向かって昇順に並んでおり、さらに下のレベルほど、その上のレベルより大きな値を持つという特徴があります。アルゴリズムの考え方この問題は、レベル順走査(幅優先探索:BFS)を用いることで効率的に解決できます。手順は以下の通りです。キューを使ってレベル順にノードを走査します。現在のレベルの最小値(min_val)と最大値(max_val)を記録します。前のレベルの最大値を保持す
-
C++で二分木がレベルごとにソートされているかどうかを判定する方法
この記事では、二分木(バイナリツリー)がレベルごとにソートされているかどうかを確認する方法を解説します。レベルごとにソートされた二分木とは、次のような構造を持つ木のことです。各レベル内では、ノードが左から右に向かって昇順に並んでおり、さらに下のレベル(層)ほど、その上のレベルより大きな値を持つという特徴があります。アルゴリズムの考え方この問題は、レベル順走査(幅優先探索)を用いることで効率的に解決できます。手順は以下の通りです。1. レベル順走査を実行しながら、現在のレベルの最小値と最大値を記録します。2. 別の変数 prevMax を用意し、直前のレベルの最大値を保持します。3. 現在のレベ