利用前序和中序数组构造二叉树
思路: 构造一颗二叉树一定要用递归+hash查找
-
找根 :从
preorder中按prel拿出一个节点作为根。 -
切分 :拿着这个根的值,去
inorder中找到它的位置index。- 计算左子树的节点个数 =
index - in_left(中序左边界)。
- 计算左子树的节点个数 =
-
递归 :根据上面算出的节点个数,把
preorder和inorder切分成左右两部分,分别递归构造左子树和右子树。 -
优化(关键) :因为每次都要在
inorder中找根的位置,如果每次都用for循环找,时间复杂度会退化到 O(n2)O(n2)。我们可以用HashMap提前把inorder里"值 -> 下标"的映射存起来,这样找根的时间就变成了 O(1)O(1)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
@param preorder 先序数组
- @param preL 当前子树在先序数组中的左边界
- @param preR 当前子树在先序数组中的右边界
- @param inL 当前子树在中序数组中的左边界
- @param inR 当前子树在中序数组中的右边界
class Solution {
private Map<Integer,Integer> indexmap=new HashMap<>();
private TreeNode build(int\[\] preorder,int prel,int prer,int inl,int inr){
if(prer<prel||inl>inr)return null;
int rootval=preorderprel;
TreeNode root=new TreeNode(rootval);
int indexin=indexmap.get(rootval);
int leftsize=indexin-inl;
root.left=build(preorder,prel+1,prel+leftsize,inl,indexin-1);
root.right=build(preorder,prel+leftsize+1,prer,indexin+1,inr);
return root;
}
public TreeNode buildTree(int\[\] preorder, int\[\] inorder) {
int n=preorder.length;
for(int i=0;i<n;i++){
indexmap.put(inorderi,i);
}
return build(preorder,0,n-1,0,n-1);
}
}
树上求路径和为指定数的路径条数
思路:树上前缀+Hsah
-
前缀和定义 :从根节点走到当前节点的路径和记为
curSum。那么,如果存在某个祖先节点,从根走到那个祖先节点的路径和是oldSum。 -
魔法公式 :如果
curSum - oldSum = targetSum,这就意味着从那个祖先节点到当前节点的这段路径和,刚好等于targetSum。- 变形一下:
oldSum = curSum - targetSum。
- 变形一下:
-
哈希表的作用 :我们在向下遍历的过程中,用一个
HashMap记录当前路径上(从根到当前节点)所有前缀和出现的次数。 -
回溯(恢复现场) :当我们处理完一个节点的左右子树,准备返回它的父节点时,必须把当前节点的
curSum从哈希表里减掉。因为当前节点已经不在我们要探索的下一条路径上了,不能影响其他分支的计算。
细节:
1.为避免树是单链表形式且结点值很大时导致前缀和溢出出现负数,map里的key前缀和要使用long类型
2.初始化:前缀和要先初始化map{0L,1};否则会出现漏掉
3.cursum是当前这条路径从根节点到当前节点的前缀和,当改变一条路径时,必须回溯
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private int dfs(TreeNode node,long cursum,int targetSum,Map<Long,Integer> premap){
if(node==null)return 0;
cursum+=node.val;
int count=premap.getOrDefault(cursum-targetSum,0);
premap.put(cursum,premap.getOrDefault(cursum,0)+1);
count+=dfs(node.left,cursum,targetSum,premap);
count+=dfs(node.right,cursum,targetSum,premap);
premap.put(cursum,premap.get(cursum)-1);
return count;
}
public int pathSum(TreeNode root, int targetSum) {
Map<Long,Integer> premap=new HashMap<>();
premap.put(0L,1);
return dfs(root,0L,targetSum,premap);
}
}