106. インオーダーおよびポストオーダートラバーサルからバイナリツリーを構築する
2 つの整数配列inorderとpostorder (inorder はバイナリ ツリーの順序トラバーサル、postorderは同じツリーのポストオーダー トラバース) が与えられた場合、バイナリ ツリーを構築して返します。
例 1:
入力: inorder = [9,3,15,20,7]、postorder = [9,15,7,20,3]
出力: [3,9,20,null,null,15,7]
例 2:
入力: inorder = [-1]、postorder = [-1]
出力: [-1]
制約:
- 1 <= inorder.length <= 3000
- postorder.length == inorder.length
- -3000 <= inorder[i]、postorder[i] <= 3000
- inorder と postorder は一意の値で構成されます。
- postorder の各値は inorder にも表示されます。
- inorder はツリーの順序走査であることが保証されます。
- postorder は、ツリーの postorder 走査であることが保証されます。
From: LeetCode
Link: 106. インオーダーおよびポストオーダートラバーサルからバイナリツリーを構築する
解決:
アイデア:
- 通信販売の横断的洞察:
- ポストオーダー トラバーサルでは、最後の要素は常にツリー (またはサブツリー) のルートになります。
- インオーダートラバーサルインサイト:
- インオーダートラバーサルでは、(ポストオーダートラバーサルから) ルートを見つけると、インオーダーリスト内のルートの左側にあるものはすべて左サブツリーとなり、右側にあるものはすべて右サブツリーになります。
これらの洞察を踏まえて、段階的なアプローチを次に示します。
- まず、ポストオーダー リストの最後の要素を使用してツリーのルートを特定します。
- 順序リストでこのルートを検索して、左右のサブツリー間の境界を決定します。
- 上記の手順を左と右のサブツリーに再帰的に適用します。
- 左側のサブツリーの場合: ルートより前の inorder リストの部分と、postorder リストの対応する要素を使用します。
- 右側のサブツリーの場合: inorder リストのルート以降の部分と、postorder リストの対応する要素を使用します。
- inorder リストの開始インデックスが終了インデックスより大きい場合、再帰を停止します。
関数 build は、ツリーを構築する再帰的なヘルパー関数です。考慮すべき順序リストの現在の境界 (開始インデックスと終了インデックス) を受け入れます。また、再帰呼び出しごとにデクリメントされる、ポストオーダー リスト内の現在のインデックスへのポインターも受け入れます。
関数 buildTree は、ツリーの構築を開始するメイン関数です。postorder インデックスを最後の要素に設定し、build 関数を呼び出すことでプロセスが開始されます。
コード:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* build(int* inorder, int inStart, int inEnd,
int* postorder, int* postIndex) {
// Base condition
if (inStart > inEnd) return NULL;
// Allocate memory for the new node
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
// The current postIndex is the value of the root for this subtree
node->val = postorder[*postIndex];
node->left = NULL; // Initialize left child to NULL
node->right = NULL; // Initialize right child to NULL
(*postIndex)--;
// If there's no left or right children, return the node
if (inStart == inEnd) return node;
// Find the index of the current node in inorder to split left and right subtree
int inIdx;
for (inIdx = inStart; inIdx <= inEnd; inIdx++) {
if (inorder[inIdx] == node->val) break;
}
// Recursively build the right and then the left subtree
node->right = build(inorder, inIdx + 1, inEnd, postorder, postIndex);
node->left = build(inorder, inStart, inIdx - 1, postorder, postIndex);
return node;
}
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize) {
// Start from the end of postorder (which represents the root of the tree)
int postIndex = postorderSize - 1;
return build(inorder, 0, inorderSize - 1, postorder, &postIndex);
}