代码随想录第十八天|● 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

在这里插入图片描述

思路一:层序遍历

用队列储存每一层的节点数,对每一层的节点数循环,加载对应的叶子结点。
在每一个层时,将这一层的第一个节点的值存起来,就是左节点的值。一直更新就是最后一层。

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue=new LinkedList<>();
        int res=0;
        if(root!=null){
            queue.add(root);
        }
        while(!queue.isEmpty()){
            int len=queue.size();
            for(int i=0;i<len;i++){
                TreeNode node=queue.poll();
                if(i==0){
                    res=node.val;
                }
                if(node.left!=null)queue.add(node.left);
                if(node.right!=null)queue.add(node.right);
            }
        }
        return res;
    }
}

思路二:递归。

如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行

那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
递归三要素:

  1. 确定递归函数的参数和返回值

参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。

本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。

  1. 确定终止条件

当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度

  1. 确定单层递归的逻辑
    因为是先左后右的递归顺序,所以当遇到叶子节点时,直接储存的就是左节点。
    设定两个全局变量深度和结果,当每一层的深度大于最大深度时,则进行更新深度,同时储存新的左节点val。
class Solution {
    int maxDeep=-1;
    int res;
    public int findBottomLeftValue(TreeNode root) {
        left(root,0);
        return res;
    }
    public void left(TreeNode root,int deep){
        if(root.left==null&&root.right==null){
            if(deep>maxDeep){
                maxDeep=deep;
                res=root.val;
            }
            // deep=root.val;
            // res=res>deep?res:deep;
        }
        if(root.left!=null){
            left(root.left,deep+1);
        }
        if(root.right!=null){
            left(root.right,deep+1);
        }
    }
}

112. 路径总和

在这里插入图片描述

思路:递归回溯找到结果

  1. 确定参数和返回类型
    在这里插入图片描述
    在这里插入图片描述
  2. 确定终止条件

首先计数器如何统计这一条路径的和呢?

不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。

如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。
如果遍历到了叶子节点,count不为0,就是没找到。

递归终止条件代码如下:count-当前节点数为0

初始代码 (递归函数单独写)

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        // List<Integer> path = new ArrayList<>();
        // int res=0;
        if(root==null){
            return false;
        }
        return traversal(root,targetSum);

    }
    private boolean traversal(TreeNode node,int count){
        if(node.left==null&&node.right==null){
            if(count-node.val==0){
                return true;
            }else{
                return false;
            }
        }
        if(node.left!=null){
            if(traversal(node.left,count-node.val)){
                return true;
            }
        }
        if(node.right!=null){
            if(traversal(node.right,count-node.val)){
                return true;
            }
        }
        return false;
    }
}

代码优化-主函数递归

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        // List<Integer> path = new ArrayList<>();
        // int res=0;
        if(root==null){
            return false;
        }
        if(root.left==null&&root.right==null&root.val==targetSum){
            return true;
        }
        if(root.left!=null){
            if(hasPathSum(root.left,targetSum-root.val))return true;
        }
        if(root.right!=null){
            if(hasPathSum(root.right,targetSum-root.val))return true;
        }
        return false;
    }

}

代码再简化

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        // List<Integer> path = new ArrayList<>();
        // int res=0;
        if(root==null){
            return false;
        }
        if(root.left==null&&root.right==null&root.val==targetSum){
            return true;
        }
        return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
    }
}

113. 路径总和ii

在这里插入图片描述

思路:递归

一个储存每一个路径的节点,当遇到叶子结点时,根据target是否等于路径和判断res是否要储存。
且每一次都要进行回溯,

class Solution {
    List<List<Integer>> res;
    List<Integer> path;
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        res = new ArrayList<>();
        path = new LinkedList<>();
        // if(root == null) return res; // 非空判断
        travesal(root,targetSum);
        return res;
    }
    public void travesal(TreeNode root,int targetSum){
        if(root==null)return;
        path.add(root.val);
        if(root.left==null&&root.right==null&&root.val==targetSum){
            // 路径和满足条件,储存路径
            res.add(new ArrayList<>(path));
        }
        // if(root.left!=null){
        //     travesal(root.left,targetSum-root.val);
        //     // 怎么回溯
        //     // path.removeLast();
        // }
        // if(root.right!=null){
        //     travesal(root.right,targetSum-root.val);
        //     // path.removeLast();
        // }
        travesal(root.left,targetSum-root.val);
        travesal(root.right,targetSum-root.val);
        path.removeLast();// 回溯这一次的节点
    }
}

106.从中序与后序遍历序列构造二叉树

在这里插入图片描述

理论

在这里插入图片描述
在这里插入图片描述

构建过程

在这里插入图片描述

边界定义

在这里插入图片描述

思路:(递归)

说到一层一层切割,就应该想到了递归。

来看一下一共分几步:

第一步:如果数组大小为零的话,说明是空节点了。

第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

第五步:切割后序数组,切成后序左数组和后序右数组

第六步:递归处理左区间和右区间

不难写出如下代码:(先把框架写出来)

	TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {

    // 第一步
    if (postorder.size() == 0) return NULL;

    // 第二步:后序遍历数组最后一个元素,就是当前的中间节点
    int rootValue = postorder[postorder.size() - 1];
    TreeNode* root = new TreeNode(rootValue);

    // 叶子节点
    if (postorder.size() == 1) return root;

    // 第三步:找切割点
    int delimiterIndex;
    for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
        if (inorder[delimiterIndex] == rootValue) break;
    }

    // 第四步:切割中序数组,得到 中序左数组和中序右数组
    // 第五步:切割后序数组,得到 后序左数组和后序右数组

    // 第六步
    root->left = traversal(中序左数组, 后序左数组);
    root->right = traversal(中序右数组, 后序右数组);

    return root;
}

代码

class Solution {
    Map<Integer,Integer>map;// 方便根据数值查找位置
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map=new HashMap<>();
        // 储存中序序列的数值对应的位置
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
        return findNode(inorder,0,inorder.length,postorder,0,postorder.length);

    }
    public TreeNode findNode(
        int[] inorder,int inBegin,int inEnd,int[] postorder,int pBegin,int pEnd){
            // 不满足左闭右开,说明没有元素,要返回
            if(inBegin>=inEnd ||pBegin>=pEnd){
                return null;
            }
            // 这里代码还没写
            // if(postorder.length==0)return null;
            // 根据postorder的数值找到中序序列分割点的index
            int rootIndex=map.get(postorder[pEnd-1]);
            // 构造节点
            TreeNode root = new TreeNode(inorder[rootIndex]);
            // 开始分割
            // 中序
            // 保存中序左子树个数,
            int lenofleft = rootIndex-inBegin;
            root.left=findNode(inorder,inBegin,rootIndex,postorder,pBegin,pBegin+lenofleft);
            root.right=findNode(inorder,rootIndex+1,inEnd,postorder,pBegin+lenofleft,pEnd-1);
            return root;
        }
}

105.从前序与中序遍历序列构造二叉树

在这里插入图片描述

思路:

和前一题相同

代码:

/**
 * 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 {
    Map<Integer,Integer>map;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map= new HashMap<>();
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
        return Tree(preorder,0,preorder.length,inorder,0,inorder.length);
    }
    public TreeNode Tree(int[] preorder, int preBegin,int preEnd,int[] inorder,int inBegin,int inEnd) {
        if(preBegin>=preEnd||inBegin>=inEnd){
            return null;
        }
        int rootIndex=map.get(preorder[preBegin]);
        TreeNode root=new TreeNode(inorder[rootIndex]);
        int lenofleft=rootIndex-inBegin;
        root.left=Tree(preorder,preBegin+1,lenofleft+preBegin+1,inorder,inBegin,rootIndex);
        root.right=Tree(preorder,preBegin+lenofleft+1,preEnd,inorder,rootIndex+1,inEnd);
        return root;
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值