这个问题是朋友问我的
起初这个题目是:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
他参考的网上的java代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//把前序遍历的值和中序遍历的值放到list中
List<Integer> preorderList = new ArrayList<>();
List<Integer> inorderList = new ArrayList<>();
for (int i = 0; i < preorder.length; i++) {
preorderList.add(preorder[i]);
inorderList.add(inorder[i]);
}
return helper(preorderList, inorderList);
}
private TreeNode helper(List<Integer> preorderList, List<Integer> inorderList) {
if (inorderList.size() == 0)
return null;
//前序遍历的第一个值就是根节点
int rootVal = preorderList.remove(0);
//创建跟结点
TreeNode root = new TreeNode(rootVal);
//查看根节点在中序遍历中的位置,然后再把中序遍历的数组劈两半,前面部分是
//根节点左子树的所有值,后面部分是根节点右子树的所有值
int mid = inorderList.indexOf(rootVal);
//[0,mid)是左子树的所有值,inorderList.subList(0, mid)表示截取inorderList
//的值,截取的范围是[0,mid),包含0不包含mid。
root.left = helper(preorderList, inorderList.subList(0, mid));
//[mid+1,inorderList.size())是右子树的所有值,
// inorderList.subList(mid + 1, inorderList.size())表示截取inorderList
//的值,截取的范围是[mid+1,inorderList.size()),包含mid+1不包含inorderList.size()。
root.right = helper(preorderList, inorderList.subList(mid + 1, inorderList.size()));
return root;
}
}
然后自己改写的python的代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) :
#print('*',preorder,inorder,end=" ")
if len(inorder) == 0:return None
rootval = preorder[0]
root = TreeNode(rootval)
index = inorder.index(rootval)
preorder.remove(rootval)
root.left=self.buildTree(preorder,inorder[:index])
root.right=self.buildTree(preorder,inorder[index+1:])
return root
上述两个代码 在LeetCode跑都通过了,还给出了正确答案们本地跑的时候也没问题。
咋一看 实际上没什么问题 但是 仔细调试就会发现有问题:
调试代码:
import copy
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def buildTree(self, preorder , inorder) :
print('(1)',preorder,end="\t ")
print('(2)',inorder,end=" \t")
if len(inorder) == 0:return None
rootval = preorder[0]
partion = inorder.index(rootval)
print(partion)
preorder.remove(rootval)
print("\t"*25,end=' ')
print('#3#',preorder, inorder[:partion],end=" \t")
print('#4#',preorder, inorder[partion+1:])
root = TreeNode(rootval)
root.left = self.buildTree(preorder, inorder[:partion])
root.right = self.buildTree(preorder, inorder[partion + 1:])
# root.left = self.buildTree(copy.deepcopy(preorder), inorder[:partion])
# root.right = self.buildTree(copy.deepcopy(preorder), inorder[partion+1:])
return root
def PrintFromTopToBottom(self, root):
# write code here
outList = []
queue = [root]
while queue != [] :
outList.append(queue[0].val)
if queue[0].left != None:
queue.append(queue[0].left)
if queue[0].right != None:
queue.append(queue[0].right)
queue.pop(0)
return outList
a=Solution()
s1=[3,9,20,15,7]
s2=[9,3,15,20,7]
out=a.buildTree(s1,s2)
print("result:")
print(a.PrintFromTopToBottom(out))
运行
这个问题困扰了我很久
后来在某大佬的提示下
发现时候引用的问题的,将代码改成copy.deepcopy就会抛出异常
因为python3的切片返回的是原list的引用,所以图片中指的情况,传入参数是如图的时候,实际调用的时候递归已经把这两个list修改了所以就没有抛出异常,同理java的sublist也是一样的原理,subList生成的子列表只是原列表的一个视图(参考:https://blog.csdn.net/u013254237/article/details/77504357)
正确解法:
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if len(preorder) == 0 :return
self.dict = {}
for i in range(len(inorder)):
self.dict [inorder[i]] = i
return self.rebuilt(preorder,0,len(preorder)-1,inorder,0,len(inorder)-1)
def rebuilt(self,preorder,preStart,preEnd,inorder,inStart,inEnd):
if preStart>preEnd:
return
rootval = preorder[preStart]
root = TreeNode(rootval)
if preStart == preEnd :
return root
index = self.dict[rootval]
leftNodeLen= index - inStart
rightNodeLen = inEnd - index
root.left = self.rebuilt(preorder,preStart+1,preStart+leftNodeLen,inorder,inStart,index-1)
root.right = self.rebuilt(preorder,preEnd-rightNodeLen+1,preEnd,inorder,index+1,inEnd)
return root
或者不对原数组进行操作:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//把前序遍历的值和中序遍历的值放到list中
List<Integer> preorderList = new ArrayList<>();
List<Integer> inorderList = new ArrayList<>();
for (int i = 0; i < preorder.length; i++) {
preorderList.add(preorder[i]);
inorderList.add(inorder[i]);
}
return helper2(preorderList, inorderList);
}
private TreeNode helper2(List<Integer> preorderList, List<Integer> inorderList) {
if (preorderList.size() == 0)
return null;
int rootVal = preorderList.get(0);
TreeNode root = new TreeNode(rootVal);
int mid = inorderList.indexOf(rootVal);
root.left = helper2(preorderList.subList(1, mid+1), inorderList.subList(0, mid));
root.right = helper2(preorderList.subList(mid+1, preorderList.size()),inorderList.subList(mid+1, inorderList.size()));
return root;
}
}
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if len(preorder) == 0:
return None
head = TreeNode(preorder[0])
tmp1 = inorder.index(preorder[0])
head.left = self.buildTree(preorder[1:tmp1+1], inorder[0:tmp1])
head.right = self.buildTree(preorder[tmp1+1:], inorder[tmp1+1:])
return head