今日收获:找树左下角的值,路径总和,从中序与后序遍历序列构造二叉树
1. 找树左下角的值
题目链接:513. - 力扣(LeetCode)
思路:每一层遍历前记录最左侧节点的值,然后再遍历该层节点,并把左右孩子加入队列中
方法:
class Solution {
public int findBottomLeftValue(TreeNode root) {
// 层次迭代遍历
int result=0;
Queue<TreeNode> queue=new LinkedList<>();
if (root!=null){
queue.offer(root);
}
while (!queue.isEmpty()){
int len=queue.size();
TreeNode left=queue.peek(); // 每一层的最左侧节点
result=left.val;
while(len>0){
TreeNode temp=queue.poll();
if (temp.left!=null){
queue.offer(temp.left);
}
if (temp.right!=null){
queue.offer(temp.right);
}
len--;
}
}
return result;
}
}
2. 路径总和
题目链接:112. - 力扣(LeetCode)
思路:和求所有路径那道题思路相似。如果是叶子节点计算节点之和,不是叶子节点就向下遍历,注意向下遍历结束后要回溯。
方法:
List<Integer> path=new ArrayList<>();
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root==null){
return false;
}
path.add(root.val);
// 叶子节点
if (root.left==null&&root.right==null){
return sumPath(path)==targetSum;
}
// 左右孩子
boolean isLeft=false;
if (root.left!=null){
isLeft=hasPathSum(root.left,targetSum);
path.remove(path.size()-1);
}
boolean isRight=false;
if (root.right!=null){
isRight=hasPathSum(root.right,targetSum);
path.remove(path.size()-1);
}
return isLeft||isRight;
}
public int sumPath(List<Integer> path){
int sum=0;
for (int value:path){
sum+=value;
}
return sum;
}
}
相关题目:
思路:
1. 由于path是全局变量,所以需要在满足条件时添加此时的路径副本(还得是chatgpt,马上就发现了我的问题)
2. 可以不用额外定义计算路径和的函数,只要在遍历左右子树时传入目标值减去当前节点的值
方法:
class Solution {
List<Integer> path=new ArrayList<>();
List<List<Integer>> result=new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
path(root,targetSum);
return result;
}
public void path(TreeNode root,int targetSum){
if (root==null){
return;
}
path.add(root.val);
// 叶子节点
if (root.left==null&&root.right==null){
if (sumPath(path)==targetSum){
result.add(new ArrayList<>(path));
}
}
// 左右孩子
if (root.left!=null){
path(root.left,targetSum);
path.remove(path.size()-1);
}
if (root.right!=null){
path(root.right,targetSum);
path.remove(path.size()-1);
}
}
public int sumPath(List<Integer> path){
int sum=0;
for (int value:path){
sum+=value;
}
return sum;
}
}
总结:注意Java的引用数据类型和全局变量。构造列表副本的方法。
3. 从中序与后序遍历序列构造二叉树
题目链接:106. - 力扣(LeetCode)
思路:根据后序列表中最后一个值确定根节点,由根节点在中序数组中划分左右子树的中序列表,再根据左右子树长度确定左右子树的后序列表
方法:
class Solution {
// 便于在中序数组中根据值找位置
Map<Integer,Integer> map=new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return helper(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode helper(int[] inorder,int inBegin,int inEnd,int[] postorder,int postBegin,int postEnd){
if (inBegin>=inEnd||postBegin>=postEnd){
return null;
}
int rootval=postorder[postEnd-1];
TreeNode root=new TreeNode(rootval);
// 划分中序数组
int rootIndex=map.get(postorder[postEnd-1]);
int leftNum=rootIndex-inBegin;
// 左右孩子
root.left=helper(inorder,inBegin,inBegin+leftNum,postorder,postBegin,postBegin+leftNum);
root.right=helper(inorder,rootIndex+1,inEnd,postorder,postBegin+leftNum,postEnd-1);
return root;
}
}
总结:
1. 前序和中序、后序和中序一定可以确定一颗二叉树
2. 保持循环不变量原则,数组保持左闭右开
3. 利用map集合存储中序列表中的值和对应位置,方便划分左右子树的长度。
相关题目
105. - 力扣(LeetCode)从前序与中序遍历序列构造二叉树
思路:和106题不同的是,前序列表中第一个节点是根节点,再根据此节点划分。注意递归的数组长度,区间是左闭右开
方法:
class Solution {
// 便于在中序数组中根据值找位置
Map<Integer,Integer> map=new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return helper(inorder,0,inorder.length,preorder,0,preorder.length);
}
public TreeNode helper(int[] inorder,int inBegin,int inEnd,int[] preorder,int preBegin,int preEnd){
if (inBegin>=inEnd||preBegin>=preEnd){
return null;
}
int rootval=preorder[preBegin];
TreeNode root=new TreeNode(rootval);
// 划分中序数组
int rootIndex=map.get(rootval);
int leftNum=rootIndex-inBegin;
// 左右孩子
root.left=helper(inorder,inBegin,inBegin+leftNum,preorder,preBegin+1,preBegin+leftNum+1);
root.right=helper(inorder,rootIndex+1,inEnd,preorder,preBegin+leftNum+1,preEnd);
return root;
}
}