● 654.最大二叉树
1.思路
构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。
递归三部曲:
一:确定递归函数的参数和返回值
为了减小空间复杂度,即每次递归切割数组时都需要新建数组,我直接使用了数组下标进行了对数组的切割。函数参数是存放元素的数组,数组起点,数组终点。
二:确认中止条件
如果传入的是空数组,返回null;
如果传入的数组只有一个元素,则直接创建返回该节点,不进行递归操作。
三:确认单层递归逻辑
先找到数组里的最大值,创造节点,然后分割,递归。
2.代码实现
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return tranversal(nums,0,nums.length-1);
}
public TreeNode tranversal(int[] nums,int begin, int end){
if(begin>end)//这个数组元素为0
return null;
if(begin == end){//这个数组元素个数为1
return new TreeNode(nums[begin]);
}
int maxValue=0;
int index=0;
for(int i=begin;i<=end;i++){
if(nums[i]>maxValue){
maxValue=nums[i];
index=i;
}
}
TreeNode temp= new TreeNode(maxValue);
temp.left=tranversal(nums,begin,index-1);
temp.right=tranversal(nums,index+1,end);
return temp;
}
}
● 617.合并二叉树
1.思路
方法一:递归
本题使用哪种遍历都是可以的!
1.确定递归函数的参数和返回值:
首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。
2.确定终止条件:
因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。
反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。
3.确定单层递归的逻辑:
单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。
那么单层递归中,就要把两棵树的元素加到一起。
接下来t1 的左子树是:合并 t1左子树 t2左子树之后的左子树。
t1 的右子树:是 合并 t1右子树 t2右子树之后的右子树。
最终t1就是合并之后的根节点。
方法二:迭代法/层序遍历
用队列实现,没写
2.代码实现
递归
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
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;
}
}
● 700.二叉搜索树中的搜索
1.思路
因为二叉搜索树的有序性,遍历的时候要比普通二叉树简单很多。
方法一:递归法
二叉搜索树是一个有序树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
这就决定了,二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样。
1.确定递归函数的参数和返回值
递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。
2.确定终止条件
如果root为空,或者找到这个数值了,就返回root节点。
3.确定单层递归的逻辑
看看二叉搜索树的单层递归逻辑有何不同。
因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。
如果root->val > val,搜索左子树,如果root->val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。
方法二:迭代法
因为二叉搜索树的特殊性,也就是节点的有序性,可以不使用辅助栈或者队列就可以写出迭代法。对于一般二叉树,递归过程中还有回溯的过程,例如走一个左方向的分支走到头了,那么要调头,在走右分支。
而对于二叉搜索树,不需要回溯的过程,因为节点的有序性就帮我们确定了搜索的方向。
2.代码实现
递归
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root==null||root.val==val)
return root;
TreeNode temp=null;
if(root.val>val)
{
temp=searchBST(root.left,val);
}
else if(root.val<val)
{
temp=searchBST(root.right,val);
}
return temp;
}
}
迭代法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while(root!=null){
if(root.val>val)
root=root.left;
else if(root.val<val)
root=root.right;
else
return root;
}
return null;
}
}
● 98.验证二叉搜索树
1.思路
首先一定要知道二叉搜索树的特性:
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。
方法一:递归
可以遍历成一个数组,然后判断数组是否有序。
更简洁的办法是在递归遍历的时候直接判断。
这道题目比较容易陷入两个陷阱:
1.不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。
陷阱2
样例中最小节点 可能是int的最小值,如果这样使用最小的int来比较也是不行的。
此时可以初始化比较元素为longlong的最小值。
问题可以进一步演进:如果样例中根节点的val 可能是longlong的最小值 又要怎么办呢?
**所以!!**用双指针来比较,一个指针pre指向前一个结点,后一个指针指向本结点
方法二:迭代法
看不懂
2.代码实现
class Solution {
TreeNode pre=null;
public boolean isValidBST(TreeNode root) {
if(root==null)
return true;
boolean left1=isValidBST(root.left);
if(pre!=null && pre.val>=root.val)
return false;
pre=root;
boolean right1=isValidBST(root.right);
return left1&&right1;
}
}