105. プレオーダーおよびインオーダートラバーサルシーケンスからバイナリツリーを構築する
タイトル説明[中]:
2 つの整数配列 preorder と inorder が与えられた場合、 preorder はバイナリ ツリーの事前順序トラバーサル、 inorder は同じツリーの順序トラバーサルです。バイナリ ツリーを構築し、そのルート ノードを返します。
例 1:
入力: preorder = [3,9,20,15,7]、inorder = [9,3,15,20,7]
出力: [3,9,20,null,null,15,7]
アイデア [再帰]:
例 1 のツリーを見ると、事前順序走査シーケンスは [3,9,20,15,7]、順序走査シーケンスは [9,3,15,20,7] であることがわかります
。ルート ノードは 3、左側のサブツリーの順序トラバーサルは [9]、右側のサブツリーの順序トラバーサルは [15, 20, 7] であることがわかります。事前順序トラバーサルにより、左側のサブツリーの事前順序トラバーサルは [9] 、右側のサブツリーの事前順序トラバーサルは [20、15、7] です。次に、左右のサブツリーを事前順序および順序で再帰的に走査することによって、バイナリ ツリーの構築を実現できます。
注: 各再帰の後、順序シーケンス内の現在のルート ノードの添え字を見つける必要があります。効率を向上させるために、ハッシュ テーブルを構築して、順序シーケンス内のすべてのノードの位置を保存できます。このようにして、探索時間をO(n)→O(1)と変化させることができる。
C++ コード:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
//定义一个哈希表
unordered_map<int, int> pos;
public:
TreeNode* Build(const vector<int>& preorder, const vector<int>& inorder, int pl, int pr, int il, int ir) {
if (pl > pr || il > ir) {
return nullptr;
}
//左子树中的节点数目=当前节点在中序序列的位置-中序序列的起始下标
int k = pos[preorder[pl]] - il;
// 建立根节点
TreeNode* root = new TreeNode(preorder[pl]);
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 k」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left = Build(preorder, inorder, pl + 1, pl + k, il, il + k - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root->right = Build(preorder, inorder, pl + k + 1, pr, il + k + 1, ir);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
//获取节点个数n
int n = preorder.size();
//通过哈希表来存储中序序列节点位置
for (int i = 0; i < n; i++) {
pos[inorder[i]] = i;
}
//调用二叉树的构建,切片操作
return Build(preorder, inorder, 0, n - 1, 0, n - 1);
}
};
時間/空間の複雑さ: O(n);
106. インオーダーおよびポストオーダートラバーサルシーケンスからバイナリツリーを構築する
タイトル説明[中]:
2 つの整数配列 inorder と postorder が与えられた場合、 inorder はバイナリ ツリーの inorder走査であり、 postorder は同じツリーのpostorder 走査です。このバイナリ ツリーを構築して返してください。
例 1:
入力: inorder = [9,3,15,20,7]、postorder = [9,15,7,20,3]
出力: [3,9,20,null,null,15,7]
アイデア [再帰]:
この質問では例 1 を例として取り上げます。彼の順序シーケンスは [9,3,15,20,7]、後順序シーケンスは [9,15,7,20,3] です。これら 2 つのプロパティに従って、シーケンス、事後シーケンスの最後の要素がルート ノードであることがわかっており、その後、順序シーケンスを通じて、左側のサブツリーの順序トラバーサルが [9] であることがわかり、右側のサブツリーの順序トラバーサルが [15,20] であることがわかります。 、7]。したがって、左側のサブツリーのポストオーダー シーケンスは 9 で、右側のサブツリーのポストオーダー シーケンスは [15, 7, 20] になります。これらのシーケンスを通じて左と右のサブツリーを再帰的に構築し、バイナリ ツリーを構築できます。
C++ コード:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
//定义一个哈希表
unordered_map<int, int> pos;
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
//获取节点个数n
int n = inorder.size();
//通过哈希表来存储中序序列节点位置
for (int i = 0; i < n; i++) {
pos[inorder[i]] = i;
}
//调用二叉树的构建,切片操作
return Build(inorder, postorder, 0, n - 1, 0, n - 1);
}
TreeNode* Build(vector<int>& inorder, vector<int>& postorder, int il, int ir, int pl, int pr) {
if (pl > pr || il > ir) {
return nullptr;
}
//左子树中的节点数目=当前节点在中序序列的位置-后序序列的末下标
int k = pos[postorder[pr]] - il;
// 建立根节点
TreeNode* root = new TreeNode(postorder[pr]);
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界 开始的 k - 1」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left = Build(inorder, postorder,il, il + k - 1, pl, pl + k - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+左子树节点数目+1 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位 到 右边界-1」的元素
root->right = Build(inorder, postorder, il + k + 1, ir, pl + k , pr - 1);
return root;
}
};
時間/空間の複雑さ: O(n);
112. パスの合計
タイトル説明[簡単]:
バイナリ ツリーのルート ノード root と、ターゲットの合計を表す整数の targetSum が与えられます。ツリー内にルート ノード、このパス上のすべてのノード値の合計が target と targetSum に等しいかどうかを判断します。存在する場合は true を返し、存在しない場合は false を返します。
リーフ ノードは、子ノードを持たないノードです。
例 1:
キー:root = [5,4,8,11,null,13,4,7,2,null,null,null,1]、ターゲット合計 = 22
出力: true
説明: ターゲット合計に等しいルート ノードからリーフ ノードへのパスが上の図に示されています。
アイデア [再帰]:
この質問の判断の本質は、左サブツリーまたは右サブツリーで、パス長が target の値であるパスを見つけることです。
タイトルを次のように変換します: target == root->val
C++ コード:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr)
return false;
if(root -> left == nullptr && root -> right == nullptr)
return root->val == targetSum;
return hasPathSum(root->left,targetSum - root->val) || hasPathSum(root->right,targetSum - root->val);
}
};
時間/空間の複雑さ: O(n);