二分木のレベル順走査に関するLeetCode問題

NO.116 各ノードの次の右側ポインタを埋める

完全二分木が与えられます。この木はすべての葉ノードが同じレベルにあり、各親ノードが2つの子ノードを持つ特徴があります。二分木は以下のように定義されます:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

各ノードのnextポインタを、その次の右側のノードを指すように設定してください。次の右側のノードが見つからない場合は、nextポインタをNULLに設定します。

初期状態では、すべてのnextポインタはNULLに設定されています。

例1:

<strong>入力:</strong>root = [1,2,3,4,5,6,7]
<strong>出力:</strong>[1,#,2,3,#,4,5,6,7,#]
<strong>説明:</strong>与えられた二分木は図Aのようになっており、関数は各ノードのnextポインタを、その次の右側ノードを指すように設定する必要があります(図B参照)。シリアライズされた出力はレベル順走査の順序で並べられ、同一レベルのノードはnextポインタで接続され、'#'は各レベルの終わりを示します。

例2:

<strong>入力:</strong>root = []
<strong>出力:</strong>[]

この問題の難しさは、各ノードのnextポインタを、その次の右側ノードを指すように設定することにあります。次のノードのポインタをどのように取得するか、まだ次のノードを走査していないのに、どうやってそのポインタを取得できるでしょうか?

ここでの考え方は、前のノードのポインタを保存し、そのnextポインタを現在のノードに設定することです。自然な考え方とは少し異なる、巧妙な方法ですね。

前のノードの変数を使用するため、ルートノードには前のノードがないことに注意する必要があります。

以下に完全なコードを示します。

class Solution {
public:
    Node* connect(Node* root) {
        // ノードを格納するキューを用意
        queue nodeQueue;
        if (root != nullptr) {
            nodeQueue.push(root);
        }

        // キューが空になるまで処理を続ける
        while (!nodeQueue.empty()) {
            int levelSize = nodeQueue.size(); // 現在のレベルのノード数を記録
            Node* previousNode = nullptr;    // 前のノードを指すポインタ

            // 現在のレベルのすべてのノードを処理
            for (int i = 0; i < levelSize; ++i) {
                Node* currentNode = nodeQueue.front();
                nodeQueue.pop();

                // レベルの最初のノードでない場合、前のノードのnextを現在のノードに設定
                if (previousNode != nullptr) {
                    previousNode->next = currentNode;
                }

                // 前のノードを更新
                previousNode = currentNode;

                // 子ノードをキューに追加
                if (currentNode->left != nullptr) {
                    nodeQueue.push(currentNode->left);
                }
                if (currentNode->right != nullptr) {
                    nodeQueue.push(currentNode->right);
                }
            }
            // レベルの最後のノードのnextをNULLに設定
            if (previousNode != nullptr) {
                previousNode->next = nullptr;
            }
        }
        return root;
    }
};

NO.117 各ノードの次の右側ポインタを埋めるII

二分木が与えられます:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

各ノードのnextポインタを、その次の右側のノードを指すように設定してください。次の右側のノードが見つからない場合は、nextポインタをNULLに設定します。

初期状態では、すべてのnextポインタはNULLに設定されています。

例1:

<strong>入力</strong>:root = [1,2,3,4,5,null,7]
<strong>出力:</strong>[1,#,2,3,#,4,5,7,#]
<strong>説明:</strong>与えられた二分木は図Aのようになっており、関数は各ノードのnextポインタを、その次の右側ノードを指すように設定する必要があります(図B参照)。シリアライズされた出力はレベル順走査の順序で並べられ(nextポインタで接続)、'#'は各レベルの末尾を示します。

例2:

<strong>入力:</strong>root = []
<strong>出力:</strong>[]

この問題は「二分木」とされていますが、116番の問題は「完全二分木」と言っています。しかし、アルゴリズム的には全く同じで、同じコードと同じロジックで解くことができます。

以下に完全なコードを示します。

class Solution {
public:
    Node* connect(Node* root) {
        queue nodeQueue;
        if (root != nullptr) {
            nodeQueue.push(root);
        }

        while (!nodeQueue.empty()) {
            int levelSize = nodeQueue.size();
            Node* previousNode = nullptr;

            for (int i = 0; i < levelSize; ++i) {
                Node* currentNode = nodeQueue.front();
                nodeQueue.pop();

                if (previousNode != nullptr) {
                    previousNode->next = currentNode;
                }

                previousNode = currentNode;

                if (currentNode->left != nullptr) {
                    nodeQueue.push(currentNode->left);
                }
                if (currentNode->right != nullptr) {
                    nodeQueue.push(currentNode->right);
                }
            }
            if (previousNode != nullptr) {
                previousNode->next = nullptr;
            }
        }
        return root;
    }
};

NO.104 二分木の最大深度

二分木rootが与えられた場合、その最大深度を返してください。

二分木の最大深度とは、根ノードから最も遠い葉ノードまでの最長パス上のノード数を指します。

例1:

<strong>入力:</strong>root = [3,9,20,null,null,15,7]
<strong>出力:</strong>3

例2:

<strong>入力:</strong>root = [1,null,2]
<strong>出力:</strong>2

以下に完全なコードを示します。

class Solution {
public:
    int maxDepth(TreeNode* root) {
        queue nodeQueue;
        int maxDepth = 0;

        if (root != nullptr) {
            nodeQueue.push(root);
        }

        while (!nodeQueue.empty()) {
            int levelSize = nodeQueue.size();

            // 現在のレベルのすべてのノードを処理
            for (int i = 0; i < levelSize; ++i) {
                TreeNode* currentNode = nodeQueue.front();
                nodeQueue.pop();

                // 子ノードをキューに追加
                if (currentNode->left != nullptr) {
                    nodeQueue.push(currentNode->left);
                }
                if (currentNode->right != nullptr) {
                    nodeQueue.push(currentNode->right);
                }
            }
            // 1レベルの処理が終わるたびに深度をインクリメント
            maxDepth++;
        }
        return maxDepth;
    }
};

NO.111 二分木の最小深度

二分木が与えられた場合、その最小深度を見つけてください。

最小深度とは、根ノードから最も近い葉ノードまでの最短パス上のノード数を指します。

説明:葉ノードとは、子ノードを持たないノードを指します。

例1:

<strong>入力:</strong>root = [3,9,20,null,null,15,7]
<strong>出力:</strong>2

例2:

<strong>入力:</strong>root = [2,null,3,null,4,null,5,null,6]
<strong>出力:</strong>5

以下に完全なコードを示します。

class Solution {
public:
    int minDepth(TreeNode* root) {
        queue nodeQueue;
        int currentDepth = 0;

        if (root != nullptr) {
            nodeQueue.push(root);
        }

        while (!nodeQueue.empty()) {
            int levelSize = nodeQueue.size();
            currentDepth++; // 深度をインクリメント

            for (int i = 0; i < levelSize; ++i) {
                TreeNode* currentNode = nodeQueue.front();
                nodeQueue.pop();

                // 葉ノードが見つかった場合、その深度を返す
                if (currentNode->left == nullptr && currentNode->right == nullptr) {
                    return currentDepth;
                }

                // 子ノードをキューに追加
                if (currentNode->left != nullptr) {
                    nodeQueue.push(currentNode->left);
                }
                if (currentNode->right != nullptr) {
                    nodeQueue.push(currentNode->right);
                }
            }
        }
        return 0;
    }
};

タグ: 二分木 レベル順走査 C++ LeetCode 幅優先探索

7月22日 20:28 投稿