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

● 513.找树左下角的值

文字
视频
题目

1.思路

方法一:递归

分析一下题目:在树的最后一行找到最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
递归三部曲:
1.确定递归函数的参数和返回值
参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。
本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。
2.确定终止条件
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
3.确定单层递归的逻辑
在找最大深度的时候,递归的过程中依然要使用回溯

方法二:层序遍历
模板题,可以看卡哥原文

2.代码实现

递归
class Solution {
    int maxDepth=-1;
    int value;
    public int findBottomLeftValue(TreeNode root) {
        tranverse(root,0);
        return value;
    }
    private void tranverse(TreeNode root, int depth){//depth是记录当前层数{
        if(root.left==null&& root.right==null){
            //到叶子节点
            if(depth>maxDepth)
            {
                maxDepth=depth;
                value=root.val;
            }
            return;
        }
        if(root.left!=null)
            tranverse(root.left,depth+1);
        if(root.right!=null)
            tranverse(root.right,depth+1);
        return;
    }
}

● 112. 路径总和

文字
视频
题目

1.思路

方法一:递归
可以使用深度优先遍历的方式(本题前中后序都可以,无所谓,因为中节点也没有处理逻辑)来遍历二叉树
一个找了很久的bug:
在写单层递归逻辑的时候,if(hasPathSum(root.left, targetSum-root.val)==true)后加了else return false,导致只遍历了最左边一条路径后就返回了,没有进行回溯。
方法二:用栈模拟递归
看了一遍理解了思路 没写

The provided code is a Java solution to find all the paths from the root to the leaves in a binary tree. Here’s an English explanation of the code:

TreeNode Definition:

The code defines a class TreeNode representing a node in a binary tree. Each node has an integer value (val) and references to its left and right children.
Solution Class:

The Solution class contains two methods: binaryTreePaths and Tranversal.
The binaryTreePaths method is the entry point for finding all paths in the binary tree. It initializes an empty list res to store the paths and an empty list path to temporarily store the current path being traversed. If the root is null, an empty list is returned.
It then calls the Tranversal method with the root, path, and res.
Tranversal Method:

The Tranversal method performs a depth-first traversal of the binary tree.
It takes the current node (root), the current path (path), and the list of paths (res) as parameters.
The method appends the value of the current node to the path list.
If the current node is a leaf node (both left and right children are null), it constructs a string representation of the path and adds it to the res list.
If the left child is not null, the method recursively calls itself with the left child. After the recursive call, the last element is removed from the path list (backtracking).
Similarly, if the right child is not null, the method recursively calls itself with the right child, and again, the last element is removed from the path list after the recursive call.
Return Result:

The binaryTreePaths method returns the final list of paths (res).

2.代码实现

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null)
            return false;
            int count=targetSum-root.val;
        if(root.left==null && root.right==null && count==0)
            return true;
        if(root.left==null && root.right ==null && count!=0)
            return false;
        if(root.left!=null)
            {
                if(hasPathSum(root.left, targetSum-root.val)==true)
                    return true;
            }
            if(root.right!=null)
            {
                if(hasPathSum(root.right, targetSum-root.val)==true)
                    return true;
            }
            return false ;
    }
}

● 113.路径总和ii

文字
题目

1.思路

方法一:递归
要遍历整个树,找到所有路径,所以递归函数不要返回值!

2.代码实现

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null)
            return res;
        List<Integer> path= new ArrayList<>();
        path.add(root.val);
        tranversal(root,targetSum-root.val,res,path);//传入当前结点时已减去当前的值
        return res;
    }
    public void tranversal(TreeNode temp, int count, List<List<Integer>> res, List<Integer> path){
        if(temp.left==null && temp.right==null && count==0)
        {
            //System.out.println(path);
            //res.add(path);
            res.add(new ArrayList<>(path));
        }
            
        if(temp.left ==null && temp.right == null && count!=0)
            return ;
        if(temp.left!=null){
            path.add(temp.left.val);
            tranversal(temp.left,count-temp.left.val,res, path);
            path.remove(path.size()-1);//回溯
        }
        if(temp.right!=null){
            path.add(temp.right.val);
            tranversal(temp.right,count-temp.right.val,res, path);
            path.remove(path.size()-1);//回溯
        }
        return;
    }
}

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

文字
视频
题目

1.思路

第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间

卡哥切割的时候用的是左闭右开区间,说实话我没看懂右侧为什么用end,而不是end+1,所以我用了左闭右闭区间,竟然写出来了,太牛了我也
框架

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;
}

关键就在于怎么切割
首先要切割中序数组,为什么先切割中序数组呢?
切割点在后序数组的最后一个元素,就是用这个元素来切割中序数组的,所以必要先切割中序数组。得到左子树和右子树数组(中序遍历顺序)。
此时有一个很重的点,就是中序数组大小一定是和后序数组的大小相同的(这是必然)。
所以可以根据大小来切割后序数组,得到左子树和右子树的后序遍历数组。

2.代码实现

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(postorder.length==0)
            return null;
        TreeNode temp=new TreeNode(postorder[postorder.length-1]);//找到中间节点
        //说明后序遍历数组里只有一个节点,直接返回,由上一层的左孩子或右孩子接住
        if(postorder.length==1)
            return temp;
        //否则继续切割
        int rootvalue=postorder[postorder.length-1];
        int delimiterIndex;
        //切割中序数组,找出左部分和右部分
        for(delimiterIndex=0;delimiterIndex<inorder.length;delimiterIndex++){
            if(inorder[delimiterIndex]==rootvalue)
                break;
        }
        int[] leftInorder=new int[delimiterIndex];
        System.arraycopy(inorder,0,leftInorder,0,delimiterIndex);      
        int[] rightInorder=new int[inorder.length-delimiterIndex-1];
        System.arraycopy(inorder,delimiterIndex+1,rightInorder,0,inorder.length-delimiterIndex-1);
        //把后序数组分裂为 左右子树,左子树下标0 ~ delimiterIndex-1 ,右子树 delimiterIndex+1, posterorder.length-2
        int[] leftpostorder=new int[delimiterIndex];
        System.arraycopy(postorder,0,leftpostorder,0,leftInorder.length);
        int[] rightpostorder=new int[inorder.length-delimiterIndex-1];
        System.arraycopy(postorder,leftInorder.length,rightpostorder,0,postorder.length-leftInorder.length-1);
        temp.left=buildTree(leftInorder,leftpostorder);
        temp.right=buildTree(rightInorder,rightpostorder);
        return temp;
    }
}

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

文字
视频
题目

1.思路

上一题类似的思路,不同点在于对前序遍历数组的切割思路。

2.代码实现

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder.length==0)
            return null;
        TreeNode temp=new TreeNode(preorder[0]);
        if(preorder.length==1)
            return temp;
        int rootvalue=preorder[0];
        int delimiterIndex;
        for(delimiterIndex=0;delimiterIndex<inorder.length;delimiterIndex++){
            if(inorder[delimiterIndex]==rootvalue)
                break;
        }
        //左子树中序遍历数组
        int[] leftinorder=new int[delimiterIndex];
        System.arraycopy(inorder,0,leftinorder,0,delimiterIndex);
//System.out.println("leftinorder");       
//System.out.println(Arrays.toString(leftinorder));
        右子树中序遍历数组
        int[] rightinorder=new int[inorder.length-delimiterIndex-1];
        System.arraycopy(inorder,delimiterIndex+1,rightinorder,0,inorder.length-delimiterIndex-1);
//System.out.println("rightinorder");       
//System.out.println(Arrays.toString(rightinorder));
        //左子树前序遍历数组
        int[] leftpreorder= new int[delimiterIndex];
        System.arraycopy(preorder,1,leftpreorder,0,delimiterIndex);
//System.out.println("leftpreorder");       
//System.out.println(Arrays.toString(leftpreorder));
        //右子树前序遍历数组
        int[] rightpreorder=new int[inorder.length-delimiterIndex-1];
        System.arraycopy(preorder,delimiterIndex+1,rightpreorder,0,preorder.length-delimiterIndex-1);
//System.out.println("rightpreorder");       
//System.out.println(Arrays.toString(rightpreorder));
        temp.left=buildTree(leftpreorder,leftinorder);
        temp.right=buildTree(rightpreorder,rightinorder);
        return temp;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值