一、力扣题654. 最大二叉树
给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
- 创建一个根节点,其值为
nums
中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 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;
}