代码随想录-Day19 | LeetCode654.最大二叉树、LeetCode617.合并二叉树、LeetCode700.二叉搜索树中的搜索、LeetCode98.验证二叉搜索树

文档讲解: 代码随想录
视频讲解: 《代码随想录》算法公开课-跟着Carl学算法

LeetCode654.最大二叉树

题目链接:654.最大二叉树

思路(后续优化,每次递归不需要创建新数组,在原数组基础上传递下标):与上道题同样的思路,以数组最大值进行分割,左侧为根节点左子树,右侧为根节点的右子树,然后进行递归。

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        // 找到数组里的最大值作为根节点
        int maxNum = Arrays.stream(nums).max().getAsInt();
        TreeNode root = new TreeNode(maxNum);
        if (nums.length == 1) {
            return root;
        }
        int index = getIndex(nums, maxNum);

        // 以根节点为切割点
        int[] left = Arrays.copyOfRange(nums, 0, index);
        int[] right = Arrays.copyOfRange(nums, index + 1, nums.length);

        // 递归遍历左右子树
        root.left = constructMaximumBinaryTree(left);
        root.right = constructMaximumBinaryTree(right);

        return root;
    }

    public static int getIndex(int[] arr, int value) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                return i;
            }
        }
        return -1;// 如果未找到返回-1
    }

}

LeetCode617.合并二叉树

题目链接:617.合并二叉树

思路:就按照LeetCode题目思路来做就可以。构造二叉树我们还是采用前序遍历。确定遍历顺序后,我们讨论递归三部曲:

  1. 传入参数和返回值:形参为两个二叉树的节点,返回值为处理后的节点。
  2. 终止条件:如果遍历到两个二叉树某个位置时,节点都为null,则返回空
  3. 单层递归逻辑:如果某个二叉树的节点为空,直接返回另一个二叉树节点的值除了都为空或者单个为空两种情况,剩下的就是两个二叉树同一位置的节点都不为空,直接相加。然后进行左子树和右子树的递归。
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        // 前序遍历:中 左 右
        // 终止条件:两个节点都为空
        if (root1 == null && root2 == null) {
            return null;
        }

        // 单层递归逻辑:
        // 直接将节点值相加
        // 其中一个没有时直接作为新二叉树的节点
        if (root1 == null) {
            return root2;
        }
        if (root2 == null) {
            return root1;
        }

        root1.val += root2.val;

        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);

        return root1;
    }
}

LeetCode700.二叉搜索树中的搜索

题目链接:700.二叉搜索树中的搜索

题目描述:给定二叉搜索树(BST)的根节点 root 和一个整数值 val。你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

思路:二叉搜索树符合左小右大,所以就间接确定了递归遍历的顺序。如果此时root值大于val,则向左子树去搜索;若root值小于val,就向右子树去搜索;当root值等于val,终止并返回以该节点为根的子树,否则返回空;一刷没有注意的点是递归要return,要接住此时的root,否则退出当前递归这个值就消失了

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        // 前序遍历
        // 二叉搜索树 左小右大
        // 如果root值大于val 向左子树搜索
        // 如果root值小于val 就向右子树搜索
        // 终止条件:root值等于val 返回以该节点为根的子树 否则为空
        if (root == null) {
            return null;
        }
        if (root.val == val) {
            return root;
        }

        if (root.val > val) {
            return searchBST(root.left, val);
        } else {
            return searchBST(root.right, val);
        }
    }
}

LeetCode98.验证二叉搜索树

题目链接:98.验证二叉搜索树

题目描述:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

思路:先自己思考的时候确实陷入了一个误区,认为在递归的时候将中间节点和左右子节点比较大小,满足左小右大的规则就可以,后面看了随想录确实有反例,二叉搜索树的满足的条件是:根节点的要大于整个左子树,小于整个右子树;所以说之前的想法属实是偷换概念了。随想录的思想看懂之后感觉还是挺简单的,但是第一次做这道题自己确实没想出来。首先确定递归顺序,根据二叉搜索树的定义,用中序遍历最合适。为什么?中序遍历的顺序就是左中右,所以按照这个遍历顺序,整个遍历过程是升序的,我们后面只需要判断每次遍历的节点是否比前一个节点大就可以,非常方便!所以首先在代码中设置了全局变量preNode = null,这个节点始终是root节点的前一位,同时在遍历的过程中与root节点同时移动,类似数组里的双指针。整体思路讨论完之后,下面讨论递归三部:

  1. 传入参数和返回值:传入参数为根节点,返回值为布尔类型,用来判断是否是二叉搜索树。
  2. 终止条件:当递归到空节点的时候,则返回true
  3. 单层递归逻辑:先处理左子树,将左子节点进行递归。然后处理中间节点,当preNode的值大于等于当前root的值时,就证明已经不是二叉搜索树了,我们就返回false;反之,则进一步进行递归,然后把preNode节点更新,让其始终为root节点的前一位;这里其实隐含着一个注意点。我们能不能在 if 判断中写preNode的值小于root的值,条件满足则对preNode节点更新,否则返回false,这种写法是不行的!因为我们初始时preNode赋值空节点,若用上述这种写法不会进入到条件判断语句体,直接会返回false,显然不对!所以这里要额外注意!然后正常递归处理右子树,最终函数的返回值是 left && right,当左子树和右子树同时满足真时此时才是二叉搜索树!
class Solution {
    TreeNode preNode = null; // 定义空节点初始化

    public boolean isValidBST(TreeNode root) {
        // 直观来看用中序遍历应该可以吧? 左 中 右 看遍历结果是否是升序的
        // 终止条件
        if (root == null) {
            return true;
        }

        // 左子树
        boolean left = isValidBST(root.left);
        // 中间节点
        // 递归过程中保证preNode节点始终是root的前一个节点
        // 比较两个节点的值
        if (preNode != null && preNode.val >= root.val) {
            return false;
        }
        preNode = root; // 这里的逻辑很重要 如果条件判断preNode.val < root.val 逻辑不对 只能这么写
        // 右子树
        boolean right = isValidBST(root.right);

        return left && right;

    }
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值