让自己快乐快乐才叫意义
654.最大二叉树
问题本质是「区间求最值」问题(RMQ),这里用了递归分治的解法。还有其他解法如:线段树、ST表、单调栈
递归遍历解法
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return bulid(nums, 0, nums.length - 1);
}
//直接用下标,不用创建数组
public TreeNode bulid(int[] nums, int l, int r){
if(l > r) return null;
int max = l;
for(int i = l; i <= r; i++){
if(nums[i]>nums[max]){
max = i;
}
}
TreeNode root = new TreeNode(nums[max]);
root.left = bulid(nums, l, max - 1);
root.right = bulid(nums, max + 1, r);
return root;
}
}
617.合并二叉树
深度优先遍历
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;
}
}
层次遍历
同时处理两棵树:把两个树的节点同时加入队列进行比较
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) return root2;
if(root2 == null) return root1;
Deque<TreeNode> que = new ArrayDeque<>();
que.offerFirst(root1);
que.offerFirst(root2);
while(!que.isEmpty()){
TreeNode r1 = que.pollLast();
TreeNode r2 = que.pollLast();
// 此时两个节点一定不为空,val相加
r1.val += r2.val;
// 如果两棵树左节点都不为空,加入队列
if(r1.left != null && r2.left != null){
que.offerFirst(r1.left);
que.offerFirst(r2.left);
}
// 如果两棵树右节点都不为空,加入队列,给下次循环处理
if(r1.right != null && r2.right != null){
que.offerFirst(r1.right);
que.offerFirst(r2.right);
}
// 当r1的左节点 为空 r2左节点不为空,就赋值过去
if(r1.left == null && r2.left != null) r1.left = r2.left;
// 当r1的右节点 为空 r2右节点不为空,就赋值过去
if(r1.right == null && r2.right != null) r1.right = r2.right;
}
return root1;
}
}
700.二叉搜索树中的搜索
二叉搜索树的节点是有序的,所以可以有方向的去搜索
递归遍历
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null || root.val == val) return root;
if(root.val > val) return searchBST(root.left,val);
return searchBST(root.right,val);
}
}
迭代法
- 对于二叉树:使用栈辅助实现深度优先遍历,使用队列辅助实现广度优先遍历,因为需要回溯
- 二叉搜索树不需要回溯的过程,因为节点的有序性就帮我们确定了搜索的方向
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while( root != null){
if(root.val == val) return root;
else if( root.val < val) root = root.right;
else root = root.left;
}
return root;
}
}
98.验证二叉搜索树
递归中序遍历
- 中序遍历下,输出的二叉搜索树节点的数值是有序序列。中序遍历的时候实时检查当前节点的值是否大于前一个中序遍历到的节点的值即可
- 不能单纯的比较左节点小于中间节点,右节点大于中间节点
- 寻找一个不符合条件的节点,递归遍历需要返回值
- 中序遍历,验证遍历的元素是不是从小到大
思路:
- 递归判断左子树是否为二叉搜索树;
- 判断中序遍历的元素是不是从小到大(图中的10和13);
- 递归判断右子树是否为二叉搜索树(图中14大于15,说明10的右子树不是二叉搜索树);
换一种思路理解:第二步的操作只是判断了中序遍历数组当前节点到上个节点是否递增,而没有判断当前节点的左边区间和右边区间是不是递增,这些就交给了递归去判断
class Solution {
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
boolean lValid = isValidBST(root.left);
if( pre!= null && pre.val >= root.val) return false;
pre = root;
boolean rValid = isValidBST(root.right);
return lValid && rValid;
}
}
//优化,左子树不是二叉搜索树就直接返回false
class Solution {
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
if(!isValidBST(root.left)) return false;
if( pre!= null && pre.val >= root.val) return false;
pre = root;
return isValidBST(root.right);
}
}
迭代中序遍历
class Solution {
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
Deque<TreeNode> st = new ArrayDeque<>();
TreeNode cur = root;
TreeNode prev = null;
while(cur != null || !st.isEmpty()){
if(cur != null){
st.offerFirst(cur);
cur = cur.left;
}else {
cur = st.pollFirst();
if(prev != null && prev.val >= cur.val) return false;
prev = cur;
cur = cur.right;
}
}
return true;
}
}