leetcode 654.最大二叉树 、617.合并二叉树 、700.二叉搜索树中的搜索 、98.验证二叉搜索树
leetcode 654 最大二叉树
题目链接:https://leetcode.cn/problems/maximum-binary-tree/description/
题目:
给定一个不重复的整数数组 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 的节点。
- 空数组,无子节点。
- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
示例 2:
输入:nums = [3,2,1]
输出:[3,null,2,null,1]
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums 中的所有整数 互不相同
解题思路
这道题其实和从中序和后序遍历以及前序和中序遍历构建二叉树的差不多的。就是在传参时候,要把左右子树的边界值给传进去。这道题的左右子树的区间比较好判断。找到最大值maxval和最大值所在的下表maxIndex,然后左边就是左子树,右边就是右子树。然后递归下去就行了。那递归终止条件就是当右边小于等于左边了。具体代码为:
代码:
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return construct(nums,0, nums.length);
}
public TreeNode construct(int[] nums,int left,int right) {
if (right - left < 1) return null; //递归终止条件
if (right - left == 1) return new TreeNode(nums[left]); //数组只有一个值
int maxIndex = left; //定义最大值的下标
int maxVal = nums[maxIndex]; //初始化最大值
for (int i = left; i < right; i++) { //找到最大值和最大值所在的下表
if (nums[i] > maxVal) {
maxIndex = i;
maxVal = nums[i];
}
}
TreeNode root = new TreeNode(maxVal); //以最大值为根节点构建二叉树
root.left = construct(nums,left,maxIndex); //左子树,区间为[left,maxIndex)
root.right = construct(nums,maxIndex + 1,right); //右子树,区间为[maxIndex+1,right]
return root; //返回结果
}
}
leetcode 617 合并二叉树
题目链接:https://leetcode.cn/problems/merge-two-binary-trees/description/
题目
给你两棵二叉树: 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
解题思路
这道题是合并两棵树,也就是说遍历的时候是两棵树同时一起遍历。可以使用前序遍历来解答。就是在遍历过程中,得判断一下节点是否有空。可以以一棵树为基础如root1,当root1的左节点为空,root2的左节点不为空,那直接把root2的左节点z指向root1,当成root1的左节点不就行了。类似的右节点也一样。然后都不为空,直接把root2的值添加到root1上,然后把返回root1就行了。其实上面也是递归的终止条件。当然也可以是构建一个新的节点,然后递归去构建一棵树。具体代码为:
代码:
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2; //root1为空,直接返回root2
if (root2 == null) return root1; //root2为空,直接返回root1
TreeNode root = new TreeNode(root1.val + root2.val); //节点值相加,构建新节点
root.left = mergeTrees(root1.left,root2.left); //左节点
root.right = mergeTrees(root1.right,root2.right); //右节点
return root; //返回结果
}
}
这道题也可以用层序遍历和迭代做。其实思想都是一样的,就是当root1的左节点为空,root2的左节点不为空,那直接把root2的左节点z指向root1,当成root1的左节点不就行了。类似的右节点也一样。然后都不为空,直接把root2的值添加到root1上,然后把返回root1就行了。只是注意一些细节。这里给出用栈和队列来做的实现代码:
//队列
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2;
if (root2 == null) return root1;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root1);
q.offer(root2);
while (!q.isEmpty()) {
TreeNode node1 = q.poll();
TreeNode node2 = q.poll();
node1.val += node2.val;
if (node1.left != null && node2.left != null) {
q.offer(node1.left);
q.offer(node2.left);
}
if (node1.right != null && node2.right != null) {
q.offer(node1.right);
q.offer(node2.right);
}
if (node1.left == null && node2.left != null) node1.left = node2.left;
if (node1.right == null && node2.right != null) node1.right = node2.right;
}
return root1;
}
}
//栈
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2;
if (root2 == null) return root1;
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root2);
stack.push(root1);
while (!stack.isEmpty()) {
TreeNode node1 = stack.pop();
TreeNode node2 = stack.pop();
node1.val += node2.val;
if (node2.right != null && node1.right != null) {
stack.push(node2.right);
stack.push(node1.right);
}else {
if (node1.right == null) {
node1.right = node2.right;
}
}
if (node1.left != null && node2.left != null) {
stack.push(node2.left);
stack.push(node1.left);
}else {
if (node1.left == null) {
node1.left = node2.left;
}
}
}
return root1;
}
}
从上面代码也可以发现具体的逻辑是一样的,就是在栈和队列处理节点不一样而已。
leecode 700 二叉搜索树中的搜索
题目链接:https://leetcode.cn/problems/search-in-a-binary-search-tree/description/
题目
给定二叉搜索树(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
解题思路
需要在BST中找到节点值等于给定值的节点,返回该节点的子树。首先因为题目说是二叉搜索树,那什么是二叉搜索树呢?
二叉搜索树是一个有序树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉搜索树
那能否用二叉搜索树的特性去解决呢。那是肯定的。其实在二叉搜索树上找元素或者比较元素,跟二分查找是一样。当val小于root.val,那就去root的左子树找,大于root.val,就与root的右子树找。具体实现代码为:
代码
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null) return root;
if (root.val == val) return root; //找到,直接返回
TreeNode node = null; //用一个节点来接收左右子树的返回值
if (root.val > val) {
System.out.println(root.val);
node = searchBST(root.left,val); //左子树
}else {
node = searchBST(root.right,val); //右子树
}
return node; //返回结果
}
}
同时也可以用迭代法,那二叉搜索树的迭代法也是一样的,因为它的特性就是这样,具体代码为:
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;
}
}
同样的,既然是二叉树,也可以用普通二叉树的遍历也解答,可以使用中序遍历也解答
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) return root; // 中
TreeNode left = searchBST(root.left,val); //左
if (left != null) return left;
TreeNode right = searchBST(root.right,val); //右
if (right != null) return right;
return null;
}
}
leetcode 98 验证二叉搜索树
题目:
解题思路
二叉搜索树的中序遍历就是一个递增的序列。所以可以利用中序遍历将节点值记录下来,然后判断,当出现前一个数值比后一个数值大,则就不是二叉搜索树。
当然,还是一种常用的方法,相当于是链表的双指针。就是说先定义一个空节点,让其直接之前的节点pre。在遍历过程直接判断pre节点的值和当前节点的值。具体代码为:
代码:
class Solution {
TreeNode max;
public boolean isValidBST(TreeNode root) {
if (root == null) return true; //树为空也是二叉搜索树
boolean left = isValidBST(root.left);//左
if (max != null && max.val >= root.val) return false; //中 比较,注意条件上要加上max!=null
max = root; //节点继续指向已经比较完的节点
boolean right = isValidBST(root.right); //右
return left && right; //返回结果
}
}
//中序遍历判断大小:
class Solution {
List<Integer> res = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
res.clear();
traverse(root);
for (int i = 1; i < res.size(); i++) {
if (res.get(i) <= res.get(i-1)) return false;
}
return true;
}
public void traverse(TreeNode root) {
if (root == null) return;
traverse(root.left);
res.add(root.val);
traverse(root.right);
}
}