(JAVA版)leetcode算法之路树篇(二)二叉搜索树相关

一、题目

235. 二叉搜索树的最近公共祖先501. 二叉搜索树中的众数98. 验证二叉搜索树230. 二叉搜索树中第K小的元素538. 把二叉搜索树转换为累加树1008. 前序遍历构造二叉搜索树99. 恢复二叉搜索树1305. 两棵二叉搜索树中的所有元素

二、解析

2.1 二叉搜索树

  • 结点左子树中所含节点的值 小于(等于) 当前节点的值
  • 结点右子树中所含节点的值 大于(等于) 当前节点的值
  • 左子树和右子树都是二叉搜索树
  • 有没有等于主要看具体题目

 2.2 思路

二叉搜索树的题目一般都是用它的两个性质,第一个就是节点大小,第二个就是中序遍历是个有序队列

2.2.1 节点大小 

235. 二叉搜索树的最近公共祖先

对于两个点的最近公共祖先这个点的值肯定是大于左节点小于右节点。所以从根节点开始遍历就行,当前节点的值大于这两个值,将当前节点移动到它的左子节点,反之亦然向右子树移动直到这个节点的值符合条件

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        TreeNode ancestor = root;
        while (true) {
            if (p.val < ancestor.val && q.val < ancestor.val) {
                ancestor = ancestor.left;
            } else if (p.val > ancestor.val && q.val > ancestor.val) {
                ancestor = ancestor.right;
            } else {
                break;
            }
        }
        return ancestor;
    }
}

98. 验证二叉搜索树

如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值,所以每个节点都有一个范围,如果超出这个范围则不是二叉搜索树,每次递归这个范围的上限或者下限会变,递归调用左子树上限就是这个root.val;调用右子树下限是root.val;

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean isValidBST(TreeNode node, long lower, long upper) {
        if (node == null) {
            return true;
        }
        if (node.val <= lower || node.val >= upper) {
            return false;
        }
        return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);
    }
}

1008. 前序遍历构造二叉搜索树

前序遍历的每一个节点都是中间节点root,那就能通过遍历一次得出当前root的左右节点(第一个大于root.val的是右节点小于的是左节点),然后递归得到每个节点的左右子树

class Solution {

    public TreeNode bstFromPreorder(int[] preorder) {
     TreeNode root=new TreeNode(preorder[0]);
     int l=0;
     mid(root,preorder,l,preorder.length);
    return root;
    }
    public void mid(TreeNode node,int[] preorder,int l,int r){
           int pr=0;
        if(node==null)
            return;
        for (int i = l; i < r; i++) {
            if(node.val>preorder[i]){
                l=i;
                node.left=new TreeNode(preorder[i]);
                break;
            }
        }
        for (int i = l; i < r; i++) {
            if(node.val<preorder[i]){
                pr=r;
                r=i;
                node.right=new TreeNode(preorder[i]);
                break;
            }
        }
        mid(node.left,preorder,l,r);
        mid(node.right,preorder,r,pr); 
    }
}

2.2.2中序遍历

501. 二叉搜索树中的众数98. 验证二叉搜索树230. 二叉搜索树中第K小的元素99. 恢复二叉搜索树1305. 两棵二叉搜索树中的所有元素

#230. 二叉搜索树中第K小的元素
class Solution {
        int i=0;
    int r;
    public int kthSmallest(TreeNode root, int k) {
        mid(root, k);
        return r;
    }
    public void mid(TreeNode root,int k){
        if(root==null)
            return;
        mid(root.left,k);
        i++;
        if(i==k)
            r=root.val;
        mid(root.right, k);
    }
}

538. 把二叉搜索树转换为累加树(右中左遍历)

class Solution {
    int sum = 0;

    public TreeNode convertBST(TreeNode root) {
        if (root != null) {
            convertBST(root.right);
            sum += root.val;
            root.val = sum;
            convertBST(root.left);
        }
        return root;
    }
}

这一部分没什么好说的,中序遍历后得到一个有序队列,然后在这基础上进行各种操作

不过有一种moris中序遍历可以节省空间,就是相当于有个前缀指针

public class MorrisTraversal {
    public void inorderTraversal(TreeNode root) {
        TreeNode current = root;
        TreeNode mostRight = null;
 
        while (current != null) {
            // If there is no left child, print the current node and move to the right child.
            if (current.left == null) {
                System.out.println(current.val);
                current = current.right;
            } else {
                // Find the most right child of the current node's left subtree
                mostRight = current.left;
                while (mostRight.right != null && mostRight.right != current) {
                    mostRight = mostRight.right;
                }
 
                // If the right pointer of the most right child is null, link it to the current node,
                // and go to the left child.
                if (mostRight.right == null) {
                    mostRight.right = current;
                    current = current.left;
                } else {
                    // If the right pointer of the most right child is not null, it means we have
                    // already visited the left subtree. Print the current node and move to the right child.
                    System.out.println(current.val);
                    mostRight.right = null; // Remove the link.
                    current = current.right;
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值