算法训练day15 | php | 654.最大二叉树 , 617.合并二叉树 , 700.二叉搜索树中的搜索 , 98.验证二叉搜索树

一、力扣题654. 最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树 

示例 1:

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

示例 2:

输入:nums = [3,2,1]
输出:[3,null,2,null,1]

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000
  • nums 中的所有整数 互不相同

         可知每次从数组中选取中节点时,都要选取数组中最大的值作为中节点,该值左边设为左子树,右边为右子树,又设计到了切割。

        整理一下,递归参数:一个数组; 终止条件:数组;返回参数:在数组中找到的最大值对应的中节点。

        单层递归逻辑:判断是否符合终止条件,不符合后,获取数组中的最大值和其下标,切割数组得到左子树和右子树的数组,分别递归左右子树的数组,将最大值赋给新节点,将该节点返回给上一层。

function constructMaximumBinaryTree($nums) {
        if(!$nums) return null;

        $sub = $this->max($nums);
        $leftNums = array_slice($nums, 0, $sub);
        $rightNums = array_slice($nums, $sub + 1);


        $cur = new TreeNode($nums[$sub]);
        $cur->left = $this->constructMaximumBinaryTree($leftNums);
        $cur->right = $this->constructMaximumBinaryTree($rightNums);

        return $cur;
    }


    function max($arr) {
        $max = $arr[0];
        $sub = 0;
        for($i = 0; $i <count($arr); $i++) {
            if($arr[$i] > $max) {
                $max = $arr[$i];
                $sub = $i;
            }
        }
        return $sub;
    }

二、力扣题617. 合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

提示:

  • 两棵树中的节点数目在范围 [0, 2000] 内
  • -104 <= Node.val <= 104

        先定义一个新节点,来承担两个二叉树的共同值。当遍历节点时,先归纳一下共有多少中可能:

        1、root1 和 root2 都为空,则指向null。

        2、root1 不为空,root2 为空,直接指向root1

        3、root2 不为空,root1 为空,直接指向root2

        4、都不为空,指向两者之和的节点

以上就是单层递归逻辑中的判断部分,然后再分别递归root1和root2的两个左节点、两个右节点,把返回的节点赋给新节点的左右节点。

function mergeTrees($root1, $root2) {
        if(!$root1 && !$root2) return null;

        $root = new TreeNode(0);
        if($root1) $root->val += $root1->val;
        if($root2) $root->val += $root2->val;

        $root->left = $this->mergeTrees($root1->left, $root2->left);
        $root->right = $this->mergeTrees($root1->right, $root2->right);

        return $root;
    }

        也可以直接把其中一个二叉树作为合并主体,这样更省空间。

function mergeTrees($root1, $root2) {
        if($root1 === null) return $root2;
        if($root2 === null) return $root1;

        $root1->val += $root2->val;
        $root1->left = $this->mergeTrees($root1->left, $root2->left);
        $root1->right = $this->mergeTrees($root1->right, $root2->right);

        return $root1;
    }

三、力扣题700. 二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

示例 1:

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

示例 2:

输入:root = [4,2,7,1,3], val = 5
输出:[]

提示:

  • 数中节点数在 [1, 5000] 范围内
  • 1 <= Node.val <= 107
  • root 是二叉搜索树
  • 1 <= val <= 107

         搜索本身不难,二叉搜索树的搜索就更简单了。

方法一:递归法

        从根节点开始,节点的值大于目标值就遍历左节点,小于目标值就遍历右节点,等于目标值就返回该节点,最后找不到就返回null。

function searchBST($root, $val) {
        if($root->val == $val) return $root;
        if($root->left == null && $root->right == null) return null;
        if($root->val > $val)
            return $this->searchBST($root->left, $val);
        if($root->val < $val)
            return $this->searchBST($root->right, $val); 
    }

方法二:迭代法 

         一个简单的循环。

function searchBST($root, $val) {
        while($root) {
            if($root->val == $val) return $root;
            if($root->val > $val) $root = $root->left;
            if($root->val < $val) $root = $root->right;
        }
        return null;
    }

方法三:迭代法2:层序遍历 

        使用队列来进行层序遍历,与上面递归法的逻辑类似,递归是只遍历符合条件的节点,这里是只将符合条件的节点放入队列,之后再拿出来遍历。

function searchBST($root, $val) {
        $queue = new splQueue();
        if(!$root) return null;
        $queue->enqueue($root);

        while(!$queue->isEmpty()) {
            $size = $queue->count();
            while($size--) {
                $cur = $queue->dequeue();
                if($cur->val == $val) return $cur;
                if($cur->val > $val && $cur->left) $queue->enqueue($cur->left);
                if($cur->val < $val && $cur->right) $queue->enqueue($cur->right);
            }
        }

        return null;
    }

四、力扣题98. 验证二叉搜索树

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

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:root = [2,1,3]
输出:true

示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 104] 内
  • -231 <= Node.val <= 231 - 1

         这道题的条件很复杂,右节点需要大于父节点,若父节点为爷爷节点的左节点,则需要小于爷爷节点。

方法一:转化为数组

        先把二叉树用中序遍历的方式转化为数组,若该二叉树符合二叉搜索树的标准,则该数组一定是升序排列。只要验证出该数组不是升序数组,则说明不符合。

class Solution {
    private $arr = [];
    /**
     * @param TreeNode $root
     * @return Boolean
     */
    function isValidBST($root) {
        $this->getArr($root);
        for($i = 0; $i < count($this->arr) - 1; $i++) {
            if($this->arr[$i] >= $this->arr[$i + 1]) return false;
        }
        return true;
    }

    function getArr($root) {
        if(!$root) return;
        $this->getArr($root->left);
        $this->arr[] = $root->val;
        $this->getArr($root->right);
    }
}

方法二:递归法

        相应的,也可以在中序遍历二叉树时,直接判断其是否是升序排列,需要设置一个全局变量来存放遍历到的节点的上一个节点的值,若前节点大于等于当前节点,则说明不符合条件,反之符合。 

function isValidBST($root) {
        if(!$root) return true;
        
        $left = $this->isValidBST($root->left);

        if($this->pre !== null && $this->pre >= $root->val) return false;
        $this->pre = $root->val;

        $right = $this->isValidBST($root->right);

        return $left && $right;
    }

方法三:迭代法

        用栈的统一迭代的方式来实现中序遍历一样能达到同样的效果。

function isValidBST($root) {
        $stack = new splStack();
        $stack->push($root);
        $pre = null;

        while(!$stack->isEmpty()) {
            $cur = $stack->pop();
            if($cur === null) {
                $root = $stack->pop()->val;
                if($pre !== null && $pre >= $root) return false;
                $pre = $root;
            } else {
                if($cur->right) $stack->push($cur->right);
                $stack->push($cur);
                $stack->push(null);
                if($cur->left) $stack->push($cur->left);
            }
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值