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 的节点。 - 空数组,无子节点。
思路:采用先序遍历,先找到最大数构造root结点,再根据最大数将数组分为左区间和右区间,分别构造左子树和右子树
图解:
递归三部曲:
1.确定返回值和参数类型
传入需要构造树的数组,返回构造的树
2.确定终止条件
当我们传入的数组只有一个数时,说明该数一定构造叶节点,因为本题1 <= nums.length <= 1000
所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。但是我们分割数组后需要考虑数组长度为0的情况
if(nums.length==1){
root.val=nums[0];
return root;
}
3.确定单层递归逻辑
找到最大数构造根节点,分割数组为左右区间,构造左右子树
//找到最大的数作为根节点
int val=nums[0];
int index=0;
for(int i=0;i<nums.length;i++){
if(val<nums[i]){
val=nums[i];
index=i;
}
}
root.val=val;
//构造左子树
int[] left_Tree=Arrays.copyOfRange(nums,0,index);
int[] right_Tree=Arrays.copyOfRange(nums,index+1,nums.length);
if(left_Tree.length>0) root.left=constructMaximumBinaryTree(left_Tree);
if(right_Tree.length>0) root.right=constructMaximumBinaryTree(right_Tree);
完整代码参考:
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
TreeNode root= new TreeNode(0);;
if(nums.length==1){
root.val=nums[0];
return root;
}
//找到最大的数作为根节点
int val=nums[0];
int index=0;
for(int i=0;i<nums.length;i++){
if(val<nums[i]){
val=nums[i];
index=i;
}
}
root.val=val;
//构造左子树
int[] left_Tree=Arrays.copyOfRange(nums,0,index);
int[] right_Tree=Arrays.copyOfRange(nums,index+1,nums.length);
if(left_Tree.length>0) root.left=constructMaximumBinaryTree(left_Tree);
if(right_Tree.length>0) root.right=constructMaximumBinaryTree(right_Tree);
return root;
}
}
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]
思路:本题的关键在于如何同时遍历两个二叉树,其实和遍历一个树逻辑是一样的,只不过传入两个树的节点,同时操作。
递归三要素:
1.确认返回值和参数类型
传入两个数的指针,返回合并后的树的指针
2.确定结束条件
当传入其中一颗树的指针为null时,返回另一个树的指针
3.单层递归逻辑
合并两棵树的当前结点,构造左右子树
root.val=root1.val+root2.val;
root.left=mergeTrees(root1.left,root2.left);
root.right=mergeTrees(root1.right,root2.right);
代码参考:
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null)return root2;
if(root2==null)return root1;
TreeNode root=new TreeNode(0);
root.val=root1.val+root2.val;
root.left=mergeTrees(root1.left,root2.left);
root.right=mergeTrees(root1.right,root2.right);
return root;
}
}
700. 二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点 root
和一个整数值 val
。
你需要在 BST 中找到节点值等于 val
的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null
。
示例 1:
输入:root = [4,2,7,1,3], val = 2 输出:[2,1,3]
二叉搜索树的特点是:
二叉搜索树是一个有序树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉搜索树
递归三部曲:
1.确定递归函数的参数和返回值:
递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。
2.确定终止条件:
当我们遇到空结点说明找不到该数,返回Null
当当前结点的val等于我们要找的数,就返回该节点
if(root==null) return null;
if(root.val==val)return root;
3.每层递归逻辑:
如果当前结点数小于目标数,我们search右子树
如果当前结点数大于目标数,我们search左子树
代码参考:
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root==null) return null;
if(root.val==val)return root;
if(root.val<val) return searchBST(root.right,val);
if(root.val>val) return searchBST(root.left,val);
return null;
}
}
98. 验证二叉搜索树
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左
子树
只包含 小于 当前节点的数。 - 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3] 输出:true
这道题目比较容易陷入两个陷阱:
陷阱1:
不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。
我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。
陷阱2
样例中最小节点 可能是int的最小值,如果这样使用最小的int来比较也是不行的。
此时可以初始化比较元素为long的最小值。
思路:我们采用中序遍历,二叉搜索树先序遍历的数一定是递增的,用maxValue记录当前最大值,如果当前结点的值不大于maxValue,则返回false,只有当左右子树都为二叉搜索树并且maxValue<当前结点的val,这棵树才为二叉搜索树
图解:
代码参考:
class Solution {
long maxValue=Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if(root==null)return true;
boolean bl=isValidBST(root.left);
if(maxValue<root.val){
maxValue=root.val;
}else return false;
boolean br= isValidBST(root.right);
return bl&&br;
}
}
如果测试数据中有 long的最小值,怎么办?
不可能在初始化一个更小的值了吧。 建议避免 初始化最小值,如下方法取到最左面节点的数值来比较。
用一个结点保存最大值的结点,如果该结点为null,说明之前没有最大值,也就是我们现在遍历到了最左的结点了
class Solution {
TreeNode MaxNode=null;
public boolean isValidBST(TreeNode root) {
if(root==null)return true;
boolean bl=isValidBST(root.left);
if(MaxNode!=null&&MaxNode.val>=root.val){
return false;
}else MaxNode=root;
boolean br= isValidBST(root.right);
return bl&&br;
}
}