C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でノード値の合計が最小となる二分木のレベルを求めるプログラム

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

例として、次のような二分木を考えてみましょう。

C++でノード値の合計が最小となる二分木のレベルを求めるプログラム

この場合、出力は 2 となります。なぜなら、レベル2のノードの値の合計は 4 + (-10) = -6 となり、これが全レベルの中で最小だからです。

解法のアプローチ

この問題は、幅優先探索(BFS)を使って各レベルごとにノードの値の合計を計算し、その中で最小となるレベルを記録していくことで解けます。具体的には、以下の手順に従います。

  • level := 1sum := ルートrの値ansLevel := levelansSum := sum で初期化する。
  • キュー q を定義し、ルートノード r を挿入する。
  • キュー q が空でない間、以下を繰り返す。
    • capacity := キューqのサイズ を取得する。
    • level を1増やし、sum := 0 にリセットする。
    • capacity が0になるまで以下を繰り返す。
      • キューの先頭ノードを取り出し、キューから削除する。
      • 右の子が存在する場合、sum に右の子の値を加算し、右の子をキューに挿入する。
      • 左の子が存在する場合、sum に左の子の値を加算し、左の子をキューに挿入する。
      • capacity を1減らす。
    • ansSum > sum の場合、ansSum := sumansLevel := 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) となります。

  1. C++で二分木における最大部分木の合計を求める方法

    この問題では、二分木(バイナリツリー)が与えられます。私たちのタスクは、木の中で最も大きな合計値を持つ部分木を見つけることです。 問題の概要 二分木には正の値と負の値が混在しています。その中から、ノードの合計が最大になる部分木を特定する必要があります。 例で問題を理解しよう 出力: 13 説明: 左部分木の合計:7 右部分木の合計:1 木全体の合計:13 このように、根を含む木全体の合計である「13」が最大の部分木の合計となります。 解法のアプローチ この問題を解くためには、後順走査(ポストオーダー走査)を利用します。手順は以下の通りです。 左部分木と右部分木それぞれのノードの合計を再

  2. C++で二分木の右側の葉(右葉)の合計を求める方法

    二分木が与えられたとき、その木に含まれるすべての「右葉(右側につながった葉ノード)」の値の合計を求める問題を考えてみましょう。 例えば、次のような二分木が入力として与えられた場合を考えます。 この場合の出力は 17 になります。この二分木には値が 7 と 10 の2つの右葉が存在するためです。 解決のためのアプローチ この問題は、DFS(深さ優先探索)を利用することで効率的に解くことができます。手順は以下の通りです。 dfs() 関数を定義します。引数としてノード(node)とブール値のフラグ(add)を受け取ります。 node が null の場合は、何もせずに処理を終了して戻ります。