From dd637ae78053dca50796ec1581b912c76e1452ab Mon Sep 17 00:00:00 2001 From: Yuhao Ju Date: Sat, 3 Dec 2022 10:51:01 +0800 Subject: [PATCH] =?UTF-8?q?update=200106.=E4=BB=8E=E4=B8=AD=E5=BA=8F?= =?UTF-8?q?=E4=B8=8E=E5=90=8E=E5=BA=8F=E9=81=8D=E5=8E=86=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E4=BA=8C=E5=8F=89=E6=A0=91:=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20go=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...序与后序遍历序列构造二叉树.md | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 17ba561d..94eb405b 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -34,7 +34,7 @@ ## 思路 -首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。 +首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。 如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。 @@ -236,7 +236,7 @@ private: vector leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size()); vector rightPostorder(postorder.begin() + leftInorder.size(), postorder.end()); - // 一下为日志 + // 以下为日志 cout << "----------" << endl; cout << "leftInorder :"; @@ -275,7 +275,7 @@ public: }; ``` -**此时应该发现了,如上的代码性能并不好,应为每层递归定定义了新的vector(就是数组),既耗时又耗空间,但上面的代码是最好理解的,为了方便读者理解,所以用如上的代码来讲解。** +**此时应该发现了,如上的代码性能并不好,因为每层递归定义了新的vector(就是数组),既耗时又耗空间,但上面的代码是最好理解的,为了方便读者理解,所以用如上的代码来讲解。** 下面给出用下标索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下标索引来分割) @@ -569,7 +569,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。 之前我们讲的二叉树题目都是各种遍历二叉树,这次开始构造二叉树了,思路其实比较简单,但是真正代码实现出来并不容易。 -所以要避免眼高手低,踏实的把代码写出来。 +所以要避免眼高手低,踏实地把代码写出来。 我同时给出了添加日志的代码版本,因为这种题目是不太容易写出来调一调就能过的,所以一定要把流程日志打出来,看看符不符合自己的思路。 @@ -728,25 +728,33 @@ class Solution: * Right *TreeNode * } */ +var ( + hash map[int]int +) func buildTree(inorder []int, postorder []int) *TreeNode { - if len(inorder)<1||len(postorder)<1{return nil} - //先找到根节点(后续遍历的最后一个就是根节点) - nodeValue:=postorder[len(postorder)-1] - //从中序遍历中找到一分为二的点,左边为左子树,右边为右子树 - left:=findRootIndex(inorder,nodeValue) - //构造root - root:=&TreeNode{Val: nodeValue, - Left: buildTree(inorder[:left],postorder[:left]),//将后续遍历一分为二,左边为左子树,右边为右子树 - Right: buildTree(inorder[left+1:],postorder[left:len(postorder)-1])} + hash = make(map[int]int) + for i, v := range inorder { // 用map保存中序序列的数值对应位置 + hash[v] = i + } + // 以左闭右闭的原则进行切分 + root := rebuild(inorder, postorder, len(postorder)-1, 0, len(inorder)-1) return root } -func findRootIndex(inorder []int,target int) (index int){ - for i:=0;i r { // 说明没有元素,返回空树 + return nil } - return -1 + if l == r { // 只剩唯一一个元素,直接返回 + return &TreeNode{Val : inorder[l]} + } + rootV := postorder[rootIdx] // 根据后序数组找到根节点的值 + rootIn := hash[rootV] // 找到根节点在对应的中序数组中的位置 + root := &TreeNode{Val : rootV} // 构造根节点 + // 重建左节点和右节点 + root.Left = rebuild(inorder, postorder, rootIdx-(r-rootIn)-1, l, rootIn-1) + root.Right = rebuild(inorder, postorder, rootIdx-1, rootIn+1, r) + return root } ``` @@ -761,22 +769,27 @@ func findRootIndex(inorder []int,target int) (index int){ * Right *TreeNode * } */ +var ( + hash map[int]int +) func buildTree(preorder []int, inorder []int) *TreeNode { - if len(preorder)<1||len(inorder)<1{return nil} - left:=findRootIndex(preorder[0],inorder) - root:=&TreeNode{ - Val: preorder[0], - Left: buildTree(preorder[1:left+1],inorder[:left]), - Right: buildTree(preorder[left+1:],inorder[left+1:])} + hash = make(map[int]int, len(inorder)) + for i, v := range inorder { + hash[v] = i + } + root := build(preorder, inorder, 0, 0, len(inorder)-1) // l, r 表示构造的树在中序遍历数组中的范围 return root } -func findRootIndex(target int,inorder []int) int{ - for i:=0;i r { + return nil } - return -1 + rootVal := pre[root] // 找到本次构造的树的根节点 + index := hash[rootVal] // 根节点在中序数组中的位置 + node := &TreeNode {Val: rootVal} + node.Left = build(pre, in, root + 1, l, index-1) + node.Right = build(pre, in, root + (index-l) + 1, index+1, r) + return node } ```