代码随想录【Day18】| 513. 找树左下角的值、112. 路径总和、构造二叉树(前+中,中+后)

513. 找树左下角的值

题目链接

题目描述:
给定一个二叉树,在树的最后一行找到最左边的值。

示例 1:
在这里插入图片描述
示例2:
在这里插入图片描述

难点:
递归法

思路:
这题要找

  1. 最底层
  2. 最左边

很容易就想到层序遍历

递归法的话,有点复杂
要向左找到最大深度,那么“左”比“右”先遍历,前中后序遍历都可以

时间复杂度:O()
空间复杂度:O()

//使用层序遍历,最下面一层的第一个就是要找的
class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Deque<TreeNode> que = new ArrayDeque<>();
        int res = 0;
        que.addLast(root);
        while(!que.isEmpty()) {
            int len = que.size();
            for (int i = 0; i < len; i++) {
                TreeNode cur = que.removeFirst();
                if (i == 0) res = cur.val; //记录当前层最左侧元素
                if (cur.left != null) que.addLast(cur.left);
                if (cur.right != null) que.addLast(cur.right);
            }
        }
        return res;
    }
}

//递归法
class Solution {
    int maxDepth = 0;
    int result = Integer.MAX_VALUE;
    public int findBottomLeftValue(TreeNode root) {
        result = root.val;
        traversal(root, 0);
        return result;
    }

    private void traversal(TreeNode root, int depth) {
        if (depth > maxDepth) { //遇到更大的深度就更新(因为“左”比“右”先遍历,所以深度下探最先访问左边的结点)
            maxDepth = depth;
            result = root.val;
        }

        if (root.left != null) {
            traversal(root.left, depth+1);
        }

        if (root.right != null) {
            traversal(root.right, depth+1);
        }
    }
}

时长:
20min

收获:
递归法的分析练习

还可以练习,优先掌握递归法:
110. 平衡二叉树
257. 二叉树的所有路径


112. 路径总和

题目链接

题目描述:
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 给定如下二叉树,以及目标和 sum = 22,
在这里插入图片描述
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

提示:
树中节点的数目在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

难点:
注意题目中结点的值是可以为负数的~~~

思路:
看到这题马上想到应该用递归会更好写一些
就用前序遍历吧~

要判断和targetSum的关系,递归函数中就需要有当前总和curSum
在单层递归中,要判断是否找到了叶子结点
如果找到叶子,判断总和是否相同

时间复杂度:O()
空间复杂度:O()

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) return false;
        int curSum = 0;
        return traversal(root, curSum, targetSum);
    }

    private boolean traversal(TreeNode root, int curSum, int targetSum) {
        if (root == null) return false;
        curSum += root.val;
        if (root.left == null && root.right == null) { //遍历到叶子节点
            if (curSum == targetSum) {
                return true;
            }else {
                return false;
            }
        }
        //左右子树只要有满足条件的路径就返回
        return traversal(root.left, curSum, targetSum) || traversal(root.right, curSum, targetSum);
    }
}

参考代码随想录还有更简洁的方法,其实这个减法思想在两数之和就接触到过,注意消化:

class solution {
   public boolean haspathsum(treenode root, int targetsum) {
        if (root == null) {
            return false;
        }
        targetsum -= root.val;
        // 叶子结点
        if (root.left == null && root.right == null) {
            return targetsum == 0;
        }
        if (root.left != null) {
            boolean left = haspathsum(root.left, targetsum);
            if (left) {      // 已经找到
                return true;
            }
        }
        if (root.right != null) {
            boolean right = haspathsum(root.right, targetsum);
            if (right) {     // 已经找到
                return true;
            }
        }
        return false;
    }
}

// 简洁方法
class solution {
    public boolean haspathsum(treenode root, int targetsum) {
        
        if (root == null) return false; // 为空退出
        
        // 叶子节点判断是否符合
        if (root.left == null && root.right == null) return root.val == targetsum;

        // 求两侧分支的路径和
        return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
    }
}

时长:
12min

收获:
求目标总和的减法思维

可以练习:
113. 路径总和 II


构造二叉树

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

难点:
找到切分点,递归地去构造,注意区间划分要准确,统一开闭

思路:

//中序+后序 构造二叉树
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保存中序序列的数值对应位置
            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 postBegin, int postEnd) {
        // 参数里的范围都是前闭后开
        if (inBegin >= inEnd || postBegin >= postEnd) {  // 不满足左闭右开,说明没有元素,返回空树
            return null;
        }
        int delimiterIndex = map.get(postorder[postEnd - 1]);  // 找到后序遍历的最后一个元素在中序遍历中的位置
        TreeNode root = new TreeNode(inorder[delimiterIndex]);  // 构造结点
        int lenOfLeft = delimiterIndex - inBegin;  // 保存中序左子树个数,用来确定后序数列的个数
        root.left = findNode(inorder, inBegin, delimiterIndex,
                            postorder, postBegin, postBegin + lenOfLeft);
        root.right = findNode(inorder, delimiterIndex + 1, inEnd,
                            postorder, postBegin + lenOfLeft, postEnd - 1);
        return root;
    }
}

//前序+中序 构造二叉树
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保存中序序列的数值对应位置
            map.put(inorder[i], i);
        }

        return findNode(preorder, 0, preorder.length, inorder,  0, inorder.length);  // 前闭后开
    }

    public TreeNode findNode(int[] preorder, int preBegin, int preEnd, int[] inorder, int inBegin, int inEnd) {
        // 参数里的范围都是前闭后开
        if (preBegin >= preEnd || inBegin >= inEnd) {  // 不满足左闭右开,说明没有元素,返回空树
            return null;
        }
        int delimiterIndex = map.get(preorder[preBegin]);  // 找到前序遍历的第一个元素在中序遍历中的位置
        TreeNode root = new TreeNode(inorder[delimiterIndex]);  // 构造结点
        int lenOfLeft = delimiterIndex - inBegin;  // 保存中序左子树个数,用来确定前序数列的个数
        root.left = findNode(preorder, preBegin + 1, preBegin + lenOfLeft + 1,  
                            inorder, inBegin, delimiterIndex);
        root.right = findNode(preorder, preBegin + lenOfLeft + 1, preEnd,
                            inorder, delimiterIndex + 1, inEnd);
        return root;
    }
}

时长:
20min

收获:
先构造map,每次查找直接可以获取到根节点的位置
比每次遍历整个数组找切分结点要方便~

前序和中序可以唯一确定一棵二叉树。

后序和中序可以唯一确定一棵二叉树。

那么前序和后序可不可以唯一确定一棵二叉树呢?

前序和后序不能唯一确定一棵二叉树!,因为没有中序遍历无法确定左右部分,也就是无法分割。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值