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

C++で二分木内の「子孫の値以上となるノード」を数える方法【DFS解説】

二分木の根 root が与えられたとき、「自分自身の値が、すべての子孫の値以上である」という条件を満たすノードの個数を求める問題です。

たとえば、次のような二分木が入力として与えられたとします。

C++で二分木内の「子孫の値以上となるノード」を数える方法【DFS解説】

この場合の出力は 4 になります。値が 3 のノード以外は、すべてこの条件を満たしているためです。

解き方のアプローチ

この問題は、深さ優先探索(DFS)を使うことで効率的に解けます。各ノードに対して「その部分木内の最大値」をボトムアップに返しながら、条件を満たすノードをカウントしていくのがポイントです。手順は以下のとおりです。

  • dfs() 関数を定義します。引数としてノードを受け取ります。
  • ノードが NULL の場合は 0 を返します。
  • l := dfs(ノードの左の子) を計算します。
  • r := dfs(ノードの右の子) を計算します。
  • ノードの値が max(l, r) 以上であれば、カウンタ ret を 1 増やします。
  • x := max(ノードの値, l, r) を計算し、x を返します。

メインの処理では、次のように行います。

  • ret := 0 で初期化します。
  • dfs(root) を呼び出します。
  • ret を返します。

それでは、実際の実装を見て理解を深めましょう。

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 ret;
   int dfs(TreeNode* node){
      if(!node)
         return 0;
      int l = dfs(node->left);
      int r = dfs(node->right);
      if(node->val >= max(l, r)) {
         ret++;
      }
      int x = max({node->val, l, r});
      return x;
   }
   int solve(TreeNode* root) {
      ret = 0;
      dfs(root);
      return ret;
   }
};
main(){
   Solution ob;
   TreeNode *root = new TreeNode(7);
   root->left = new TreeNode(4);
   root->right = new TreeNode(3);
   root->right->left = new TreeNode(7);
   root->right->right = new TreeNode(5);
   cout << (ob.solve(root));
}

入力

TreeNode *root = new TreeNode(7);
root->left = new TreeNode(4);
root->right = new TreeNode(3);
root->right->left = new TreeNode(7);
root->right->right = new TreeNode(5);

出力

4

計算量について

このアルゴリズムでは、各ノードを一度ずつしか訪問しないため、時間計算量は O(N)(N はノード数)です。また、再帰呼び出しの深さがスタックに積まれるため、空間計算量は木の高さに依存し、最悪の場合(線形に連なった木)で O(N) となります。

  1. C++で二分木が完全二分木かどうかを判定する方法

    完全二分木とは?二分木が与えられたとき、その木が完全二分木(Complete Binary Tree)であるかどうかを判定する問題を考えてみましょう。完全二分木とは、深さ n の木において、上から n-1 レベルまですべてのノードが埋まっており、最下層のノードは必ず左側から順に配置されている二分木のことです。例えば、次のような入力木が与えられたとします。この場合、すべてのノードが左詰めで配置されているため、出力は true(完全二分木である)になります。解法のアプローチこの問題は、幅優先探索(BFS)とフラグ変数を組み合わせることで効率的に解くことができます。具体的な手順は以下の通りです。木が

  2. C++で二分木を剪定する:1を含まない部分木を削除する再帰アルゴリズム

    問題概要二分木のルートノード root が与えられ、すべてのノードの値は 0 または 1 のいずれかであるとします。この木から、1 を含まないすべての部分木を削除した結果の木を求めるのが目的です。たとえば、次のような木が与えられた場合 −解決のためのアプローチこの問題は、再帰的な手法を用いて以下の手順で解決できます −ノードを引数として受け取る再帰メソッド solve() を定義します。処理の流れは次のとおりです −ノードが null の場合は、null を返しますノードの左の子に対して solve(左の子) を実行し、その結果を左の子に代入しますノードの右の子に対して solve(右の子)