654.最大二叉树
题目描述
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
示例1:
输入:
n
u
m
s
=
[
3
,
2
,
1
,
6
,
0
,
5
]
nums = [3,2,1,6,0,5]
nums=[3,2,1,6,0,5]
输出:
[
6
,
3
,
5
,
n
u
l
l
,
2
,
0
,
n
u
l
l
,
n
u
l
l
,
1
]
[6,3,5,null,2,0,null,null,1]
[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 的节点。
- 空数组,无子节点。
示例1:
输入: n u m s = [ 3 , 2 , 1 ] nums = [3,2,1] nums=[3,2,1]
输出: [ 3 , n u l l , 2 , n u l l , 1 ] [3,null,2,null,1] [3,null,2,null,1]
- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
思路
看半天题目都没看明白应该按啥顺序写,还得是示例的解释才能看明白。
题目说的过程中都提示递归了,再不用递归就有点不礼貌了。
先找到区间内最大值,并以此为分界线,左右分别递归,直到结束。
解法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return helper(nums,0,nums.length-1);
}
public TreeNode helper(int[]nums , int left,int right){
if(left > right) return null;
int best = left;
for(int i = left+1;i<=right;i++){
if(nums[i]>nums[best]){
best = i;
}
}
TreeNode node = new TreeNode(nums[best]);
node.left = helper(nums,left,best-1);
node.right = helper(nums,best+1,right);
return node;
}
}
总结
能递归的题自然拿迭代也能写,但我的评价是没有必要。直接模拟我觉得就是最好的结果了,能想到,而且仔细想想能写出来,看到这个题第一反应肯定不是迭代的,所以还是好好练练递归,需要的时候能写出来就好。
617. 合并二叉树
题目描述
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
示例1:
输入:
r
o
o
t
1
=
[
1
,
3
,
2
,
5
]
,
r
o
o
t
2
=
[
2
,
1
,
3
,
n
u
l
l
,
4
,
n
u
l
l
,
7
]
root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
root1=[1,3,2,5],root2=[2,1,3,null,4,null,7]
输出:
[
3
,
4
,
5
,
5
,
4
,
n
u
l
l
,
7
]
[3,4,5,5,4,null,7]
[3,4,5,5,4,null,7]
示例2:
输入:
r
o
o
t
1
=
[
1
]
,
r
o
o
t
2
=
[
1
,
2
]
root1 = [1], root2 = [1,2]
root1=[1],root2=[1,2]
输出:
[
2
,
2
]
[2,2]
[2,2]
思路
本题的思路很明确,递归应该是最简单最容易想到的,但我确实没想到可以直接改在一棵树上,最先想到的还是要整个新树,能修改还是省下空间了。
迭代的话我还是更加倾向于层序遍历吧,因为更加直观,写起来的时候也更清晰。但理论上来说应该是所有遍历都可以的。
解法1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
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;
}
}
解法2
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) return root2;
if(root2 == null) return root1;
Queue<TreeNode> que = new LinkedList<>();
que.offer(root1);
que.offer(root2);
while(!que.isEmpty()){
TreeNode node1 = que.poll();
TreeNode node2 = que.poll();
node1.val = node1.val+node2.val;
if(node1.left != null && node2.left != null){
que.offer(node1.left);
que.offer(node2.left);
}
if(node1.right != null && node2.right != null){
que.offer(node1.right);
que.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;
}
}
总结
这个题的迭代真的会值得反复观看,感觉是一个层序遍历的经典使用了。
700. 二叉搜索树
题目描述
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
示例1:
输入:
r
o
o
t
=
[
4
,
2
,
7
,
1
,
3
]
,
v
a
l
=
2
root = [4,2,7,1,3], val = 2
root=[4,2,7,1,3],val=2
输出:
[
2
,
1
,
3
]
[2,1,3]
[2,1,3]
示例2:
输入:
r
o
o
t
=
[
4
,
2
,
7
,
1
,
3
]
,
v
a
l
=
5
root = [4,2,7,1,3], val = 5
root=[4,2,7,1,3],val=5
输出:
[
]
[]
[]
思路
第一时间肯定是想到了递归,这题真的很好递归。
解法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
TreeNode cur = root;
if(cur == null) return null;
if(cur.val == val) return cur;
if(cur.val < val){
return searchBST(root.right,val);
}
return searchBST(root.left,val);
}
}
总结
能看出来的递归都是好递归!
98. 验证二叉搜索树
题目描述
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例1:
输入:
r
o
o
t
=
[
2
,
1
,
3
]
root = [2,1,3]
root=[2,1,3]
输出:
t
r
u
e
true
true
示例2:
输入:
r
o
o
t
=
[
5
,
1
,
4
,
n
u
l
l
,
n
u
l
l
,
3
,
6
]
root = [5,1,4,null,null,3,6]
root=[5,1,4,null,null,3,6]
输出:
f
a
l
s
e
false
false
思路
能很快看出递归或者中序。
递归中规定每次的上界和下界,进行判断。
中序遍历中可以看输出的是否为一个递增序列。
解法1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return helper(root,Long.MIN_VALUE,Long.MAX_VALUE);
}
public boolean helper(TreeNode node,long lower, long upper){
if(node == null){
return true;
}
if(node.val <= lower || node.val >= upper){
return false;
}
return helper(node.left,lower,node.val) && helper(node.right,node.val,upper);
}
}
解法2
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
Stack<TreeNode> stk = new Stack<>();
double inorder = -Double.MAX_VALUE;
while(!stk.isEmpty() || root != null){
while(root != null){
stk.push(root);
root = root.left;
}
root = stk.pop();
if(root.val <= inorder){
return false;
}
inorder = root.val;
root = root.right;
}
return true;
}
}
总结
测试案例,真的很绝,不得不说一句,踩中了真的踩中了类型边界值的坑。
谁能想到是因为过界了才能没过啊。看了答案才知道是这个问题。