C++で長さがK未満のルートからリーフへのパス上のノードを削除する方法
問題の概要
木構造が与えられたとき、ルートからリーフまでのパスの長さが指定された値 k 未満であるようなパスのリーフノードをすべて削除する必要があります。次の例で具体的に確認してみましょう。
入力 −
K = 4

出力 −

解説
各パスは以下のとおりです。 1. A → B → C → E(長さ = 4) 2. A → B → C → F(長さ = 4) 3. A → B → D(長さ = 3) 4. A → G → H(長さ = 3) 5. A → B → I(長さ = 3) ご覧のとおり、パス 3・4・5 の長さは 3 であり、これは与えられた k(= 4)より短いため、これらのパスのリーフノード(D、H、I)を削除します。 さらに、パス 4 と 5 では H と I を削除した結果、G 自身も新たなリーフノードとなり、その時点でのパスの長さは 2 になるため、今度はノード G を削除します。ここでプログラムは終了します。
この問題では、木を後順(ポストオーダー)走査で巡回し、パスの長さが k 未満であるリーフノードを再帰的に削除する関数を作成します。
解決のためのアプローチ
このアプローチでは、後順走査によって木を巡回しながら、パスの長さが k 未満となるリーフノードを再帰的に検出して削除し、この処理を続けていきます。
実装例
上記のアプローチを実装したC++コード
#include<bits/stdc++.h>
using namespace std;
struct Node{ // ノードの構造体
char data;
Node *left, *right;
};
Node *newNode(int data){ // 新しいノードの作成
Node *node = new Node;
node->data = data;
node->left = node->right = NULL;
return node;
}
Node *trimmer(Node *root, int len, int k){
if (!root) // root == NULL の場合はそのまま返す
return NULL;
root->left = trimmer(root->left, len + 1, k); // 左部分木を走査
root->right = trimmer(root->right, len + 1, k); // 右部分木を走査
if (!root->left && !root->right && len < k){
delete root;
return NULL;
}
return root;
}
Node *trim(Node *root, int k){
return trimmer(root, 1, k);
}
void printInorder(Node *root){
if (root){
printInorder(root->left);
cout << root->data << " ";
printInorder(root->right);
}
}
int main(){
int k = 4;
Node *root = newNode('A');
root->left = newNode('B');
root->right = newNode('G');
root->left->left = newNode('C');
root->left->right = newNode('D');
root->left->left->left = newNode('E');
root->left->left->right = newNode('F');
root->right->left = newNode('H');
root->right->right = newNode('I');
printInorder(root);
cout << "\n";
root = trim(root, k);
printInorder(root);
return 0;
}出力
E C F B D A H G I E C F B A
コードの解説
このコードでは、再帰関数を用いて木を巡回し、左部分木と右部分木の状態を常に追跡しています。リーフノードに到達した時点で、そこまでのパスの長さをチェックし、長さが k 未満であればそのノードを削除して NULL を返します。条件を満たさない場合は、そのまま処理を続行します。
まとめ
本記事では、再帰を活用して「長さが K 未満のルートからリーフへのパス上のノードを削除する」という問題を解きました。この問題に対するC++プログラム、再帰的な考え方、そして完全な解法の流れについても学びました。同じロジックは、C、Java、Python などの他の言語でも同様に実装できます。本チュートリアルが皆さんの学習のお役に立てば幸いです。
-
C++で再帰を使わずに二分木のルートからリーフまでのパスを出力する方法
二分木が与えられたとき、ルートからリーフ(葉)までの複数のパスをすべて出力する必要があります。しかし、ここでの課題は再帰を使用せずに実装することです。通常、木の探索には再帰がよく使われますが、今回は制約として再帰が使えないため、反復処理(イテレーティブな方法)で木を走査します。そのために、STLのmapを活用します。このマップには各ノードとその親ノードの対応関係を格納し、レベル順走査(またはスタックを用いた走査)によってリーフノードを検出した時点で、親へのポインタをたどることでルートからリーフまでのパスを出力できます。上記の二分木の場合、ルートからリーフまで到達するためのパスは以下のように複数
-
Pythonで解く!二分木のルートからリーフへのパスにおける不十分なノードの削除方法
問題概要 二分木が与えられたとき、あるノードが「不十分(insufficient)」であるとは、そのノードを通るすべてのルートからリーフへのパスのノード値の合計が、与えられた limit よりも厳密に小さいことを意味します。この条件を満たすすべての不十分なノードを同時に削除し、処理後の二分木のルートを返すのが本問題の目的です。 例えば、次のような二分木があり、limit = 1 が与えられたとします。 このとき、不十分なノードを削除した後の出力は以下のようになります。 解法のアプローチ この問題は、再帰(深さ優先探索)を使って効率的に解くことができます。基本的な考え方は、各リーフノードに