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

C++で二分木の最下層・左端の値を求める方法

二分木が与えられたとき、その木の最も深い行(最下層)における左端の値を求める問題を考えてみましょう。例えば、次のような二分木があるとします。

C++で二分木の最下層・左端の値を求める方法

この場合、最下層は [7, 4] であり、その中で最も左にある要素は 7 なので、出力は 7 となります。

解法のアプローチ

この問題は、深さ優先探索(DFS)を利用することでシンプルに解くことができます。ポイントは「必ず左側の子ノードから先に訪問する」ことです。こうすることで、それまでに到達した中で最も深いレベルへ最初に到達したノードが、自動的にそのレベルの左端のノードになります。

アルゴリズムの手順

  • 最初に、答えを格納する ans と、現在の最大レベルを記録する lvl という変数を用意します。
  • solve() というメソッドを定義します。このメソッドは木のノードとレベルを引数に取り、レベルの初期値は 0 です。動作は以下の通りです。
  • ノードが null の場合は何もせずに戻ります。
  • level > lvl の場合、ans にノードの値を代入し、lvl を現在のレベルで更新します。
  • solve(ノードの左の子, level + 1) を呼び出します。
  • solve(ノードの右の子, level + 1) を呼び出します。
  • メイン処理では、lvl := -1 と設定し、solve(root) を呼び出した後、ans を返します。

理解を深めるために、以下の実装を見てみましょう。

実装例

#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<auto> v){
    cout << "[";
    for(int i = 0; i<v.size(); i++){
       cout << v[i] << ", ";
    }
    cout << "]"<<endl;
}
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 ans;
    int lvl;
    void solve(TreeNode* node, int level = 0){
       if(!node || node->val == 0) return;
       if(level > lvl){
          ans = node->val;
          lvl = level;
       }
       solve(node->left, level + 1);
       solve(node->right, level + 1);
    }
    int findBottomLeftValue(TreeNode* root) {
       lvl = -1;
       solve(root);
       return ans;
    }
};
main(){
    vector<int> v = {3,5,1,6,2,0,8,NULL,NULL,7,4};
    TreeNode *tree = make_tree(v);
    Solution ob;
    cout <<(ob.findBottomLeftValue(tree));
}

入力

[3,5,1,6,2,0,8,null,null,7,4]

出力

7

計算量について

このアルゴリズムでは、各ノードを一度だけ訪問するため、時間計算量は O(n)(n はノード数)となります。また、再帰の深さは木の高さに依存するため、空間計算量は O(h)(h は木の高さ)です。最悪の場合、木が線形に偏っていると O(n) になりますが、バランスの取れた木であれば O(log n) に抑えられます。

  1. C++で二分木の各階層における最大値を見つける方法

    二分木が与えられたとき、その木の各階層(レベル)ごとの最大値を求めることを考えます。例えば、次のような二分木があるとします。この場合、出力は [1, 3, 9] となります。ルート(最上位)の階層には「1」だけが存在するため、最大値は 1第1階層には「3」と「2」があり、最大値は 3第2階層には「5」「3」「9」があり、最大値は 9解決のためのアプローチこの問題は、再帰的な深さ優先探索(DFS) を使うことで簡潔に解くことができます。手順は以下の通りです。結果を格納するための配列 ans を定義します。再帰関数 solve() を定義します。この関数はツリーノードとレベル(初期値は 0)を引数

  2. C++の二分探索木(BST)で最小値のノードを見つける方法

    二分探索木(Binary Search Tree、BST)が与えられたとき、その木の中から最小の要素を見つけることを考えます。例えば、以下のようなBSTがあるとします。この場合、最小要素は 1 になります。考え方二分探索木の重要な性質として、左部分木には必ず親ノードより小さい値が格納されるというものがあります。この性質を利用すると、次の手順で最小要素を見つけることができます。ルートノードから探索を開始します。現在のノードの左の子が NULL でない間、左の子へ移動を繰り返します。左の子が NULL になったノードの値が、木全体の中で最小の要素です。この操作の計算量は木の高さに依存し、平衡な二分