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

C++で長さがK未満のルートからリーフへのパス上のノードを削除する方法

問題の概要

木構造が与えられたとき、ルートからリーフまでのパスの長さが指定された値 k 未満であるようなパスのリーフノードをすべて削除する必要があります。次の例で具体的に確認してみましょう。

入力 −

K = 4

C++で長さがK未満のルートからリーフへのパス上のノードを削除する方法

出力 −

C++で長さがK未満のルートからリーフへのパス上のノードを削除する方法

解説

各パスは以下のとおりです。
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 などの他の言語でも同様に実装できます。本チュートリアルが皆さんの学習のお役に立てば幸いです。

  1. C++で再帰を使わずに二分木のルートからリーフまでのパスを出力する方法

    二分木が与えられたとき、ルートからリーフ(葉)までの複数のパスをすべて出力する必要があります。しかし、ここでの課題は再帰を使用せずに実装することです。通常、木の探索には再帰がよく使われますが、今回は制約として再帰が使えないため、反復処理(イテレーティブな方法)で木を走査します。そのために、STLのmapを活用します。このマップには各ノードとその親ノードの対応関係を格納し、レベル順走査(またはスタックを用いた走査)によってリーフノードを検出した時点で、親へのポインタをたどることでルートからリーフまでのパスを出力できます。上記の二分木の場合、ルートからリーフまで到達するためのパスは以下のように複数

  2. Pythonで解く!二分木のルートからリーフへのパスにおける不十分なノードの削除方法

    問題概要 二分木が与えられたとき、あるノードが「不十分(insufficient)」であるとは、そのノードを通るすべてのルートからリーフへのパスのノード値の合計が、与えられた limit よりも厳密に小さいことを意味します。この条件を満たすすべての不十分なノードを同時に削除し、処理後の二分木のルートを返すのが本問題の目的です。 例えば、次のような二分木があり、limit = 1 が与えられたとします。 このとき、不十分なノードを削除した後の出力は以下のようになります。 解法のアプローチ この問題は、再帰(深さ優先探索)を使って効率的に解くことができます。基本的な考え方は、各リーフノードに