2023.4.3 最大二叉树
思路类似于根据后序后中序数组构建二叉树。也是一个类似的过程。不同之处在于我们如何找到这个数组里面的最大值?
猜想:构建一个重复的数组,对其进行排序处理,然后将原来的数组放入哈希表中,这样我们就能根据排序后的数组来查找原数组中对应的最大元素了。
然而该猜想是错误的,因为对数组排序后会破坏其左右区间,无法判断最大值是在左子树还是右子树。
我们直接使用循环来找到最大值。
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return getRoot(nums,0,nums.length);
}
public TreeNode getRoot(int[] nums,int left,int right){
//退出递归条件,同样使用左闭右开的区间,因此退出条件就是左区间大于等于右区间
if(left >= right){
return null;
}
//通过循环来确定最大值及其下标
int maxIndex = -1;
int maxValue = -1;
for(int i = left;i<right;i++){
if(maxValue < nums[i]){
maxIndex = i;
maxValue = nums[maxIndex];
}
}
//确定好最大值后,我们就确定好了当前的根节点
TreeNode root = new TreeNode(maxValue);
//接下来要确定左子树的根节点与右子树的根节点
//确定左子树的根节点,我们的做左区间变为了left到maxIndex之间,因为是左闭右开区间
root.left = getRoot(nums,left,maxIndex);
//确定右子树根节点,我们的右区间变为了maxIndex+1到right之间
root.right = getRoot(nums,maxIndex + 1,right);
//最后返回root
return root;
}
}
2023.4.3 合并二叉树
猜想:采用递归同时操作两个节点?
返回值 TreeNode ,传入参数 两个二叉树的根节点,结束条件,两个节点都为null,递归逻辑,如果都不为null,新节点就是两个节点值相加,有一个为null就只加一个的值,两个都为null直接返回null
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
//这两个if语句已经包括了两者同时为null返回null的情况了
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;
}
}
2023.4.3 二叉搜索树中的搜索
层序遍历?可以实现,效率太低了
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int length = queue.size();
for(int i = 0;i<length;i++){
TreeNode temp = queue.poll();
if(temp.val == val){
return temp;
}
if(temp.left != null){
queue.offer(temp.left);
}
if(temp.right != null){
queue.offer(temp.right);
}
}
}
return null;
}
}
使用递归?
注意:二叉搜索树是一个有序的二叉树,它具有以下特点:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉搜索树
因此我们在搜索二叉搜索树时可以根据val值的大小进行有序的搜索。
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null){
return null;
}
if(root.val == val){
return root;
}
TreeNode res = null;
//二叉搜索树是有顺序的
if(root.val > val){
res = searchBST(root.left,val);
}
else if(root.val < val){
res = searchBST(root.right,val);
}
return res;
}
}
2023.4.3 验证二叉搜索树
验证一颗二叉树是否是二叉搜索树,我们首先要验证根节点与其左右子节点的关系,随后递归的验证其左右子节点与其子节点的关系。
很容易犯的错误代码:
原因,因为二叉搜索树的大小关系不仅仅是对左右两个子节点而言,而是对左右两个子树而言,它要求左子树上的所有节点严格小于根节点数值,右子树上的所有节点数值严格大于根节点数值。我们的代码仅仅检查了左右子节点与根节点的关系,没有考虑整体。
class Solution {
public boolean isValidBST(TreeNode root) {
if(root == null){//遍历到了叶子结点。
return true;
}
if(root.left == null && root.right != null && root.val >= root.right.val){
return false;
}
else if(root.left != null && root.right == null && root.val <= root.left.val){
return false;
}
else if(root.left != null && root.right != null && (root.val <= root.left.val || root.val >= root.right.val)){
return false;
}
return isValidBST(root.left) && isValidBST(root.left);
}
}
实际上,我们可以使用中序遍历的方法,将得到的值计入数组中,我们只需要判断这个数组是否是一个递增的数组即可。
class Solution {
List<Integer> res = new ArrayList<Integer>();
//通过中序遍历将二叉树的值放入一个链表
public void getList(TreeNode root){
if(root == null){
return;
}
getList(root.left);
res.add(root.val);
getList(root.right);
}
public boolean isValidBST(TreeNode root) {
getList(root);
int length = res.size();
for(int i = 0;i<length-1;i++){
if(res.get(i) >= res.get(i+1)){
return false;
}
}
return true;
}
}
更进一步,我们不需要采用数组来储存结果,因为中序遍历的结果就是来判断该二叉树是否是递增的,我们只需要定义一个全局变量,在递归中序遍历时来判断其每个节点的值是否是依次递增的即可
class Solution {
long max = Long.MIN_VALUE;
//通过中序遍历来确定每个当前节点的数值都比上一个数值大。这个参考数值就是我们设定的max值,max值是动态更新的。
public boolean isValidBST(TreeNode root) {
if(root == null){
return true;
}
if(!isValidBST(root.left)){
return false;
}
if(root.val <= max){
return false;
}
max = root.val;
return isValidBST(root.right);
}
}