[LeetCode]-二叉树-4

前言

记录 LeetCode 刷题中遇到的二叉树相关题目,第四篇

98.验证二叉搜索树

判断一棵二叉树是否是二叉搜索树的方法:这颗二叉树的中序遍历的结果如果是递增的,那这颗二叉树就是二叉搜索树
用一个变量 tmp 维护中序遍历时上一个访问到的数,那么下一个访问到的数应该大于 tmp,否则的话遍历出来的序列就不是递增的,也就不是二叉搜索树。题目给的节点的值是int的范围,初始化 tmp 为 Integer.MIN_VALUE - 1

class Solution {
    
    
    private long temp = (long)Integer.MIN_VALUE - 1;
    public boolean isValidBST(TreeNode root) {
    
    
        if(root == null) return true;
        if(isValidBST(root.left) == false || (long)root.val <= temp) return false;
        temp = root.val;
        return isValidBST(root.right);
    }
}

面试题 04.05. 合法二叉搜索树

合法二叉搜索树的验证方法就是:对这棵树中序遍历得到的遍历序列是一个递增序列,所以可以基于中序遍历,记录上一个被遍历到的结点的值 prv,然后判断当前要访问的结点的值是否大于 prv,不的话就能马上说明遍历序列不是一个递增序列,直接返回 false

class Solution {
    
    
    Integer prv;
    public boolean isValidBST(TreeNode root) {
    
    
        if(root == null) return true;
        if(!isValidBST(root.left)) return false;
        else if(prv != null && root.val <= prv) return false;
        prv = root.val;
        return isValidBST(root.right);
    }
}

1038. 从二叉搜索树到更大和树

每个递归状态:对于每个节点,先遍历其左子树,获取左子树上所有节点的和,然后将这个和加上当前节点的 val,得到的结果就是当前节点要被修改的值,然后就继续遍历左子树

class Solution {
    
    
    int sum = 0;
    public TreeNode bstToGst(TreeNode root) {
    
    
        if(root == null) return null; //不变的递归终点
        bstToGst(root.right);
        sum += root.val;
        root.val = sum;
        bstToGst(root.left);
        return root;
    }
}

剑指 Offer 36. 二叉搜索树与双向链表

基于中序遍历,用变量 prv 记录上一个访问到的节点,然后将当前访问的节点与其链接起来,然后更新 prv

class Solution {
    
    
	//记录头节点,以便最后将其与尾结点接在一起形成循环链表
    private Node head = null;
    private Node prv = null;
    //递归函数,中序遍历
    public void rec(Node root){
    
    
        if(root == null) return;
        treeToDoublyList(root.left);
        //由于是中序遍历,所以在访问当前节点的右孩子时,当前节点的left跟right可能被修改了,所以要先记录右孩子的地址
        Node r = root.right;
        if(prv == null){
    
      //访问到第一个节点时prv还是null
            head = root;
        }
        else{
    
     //当前节点与prv链接
            prv.right = root;
            root.left = prv;
        }
        //更新prv
        prv = root;
        treeToDoublyList(r);
    }
    public Node treeToDoublyList(Node root) {
    
    
        if(root == null)return null;
        rec(root);
        //遍历完prv就是最后一个节点 (即树中值最大的节点) ,将head与其链接
        head.left = prv;
        prv.right = head;
        return head;
    }
}

剑指 Offer 54. 二叉搜索树的第k大节点

二叉树的特征就是传统中序遍历 (即先遍历左子树再遍历根节点再遍历右子树) 的结果为递增序列,所以中序遍历中,越先被遍历到的节点,它在最终得到的遍历序列中的大小排序就越小

这种情况遍历顺序并不利于我们找到第 k 大节点 (但利于找到倒数第 k 大节点)

解决方法就是对传统的中序遍历做点调整:先遍历右子树,再遍历根节点,再遍历左子树,这样得到的遍历序列就是递减的了,不用遍历整棵树得到完整的遍历序列就能找到第 k 大节点

class Solution {
    
    
	//num表示当前遍历到的节点是树中第num大节点,当num == k的时候就说明找到了第k大节点
    int num;
    int inorder(TreeNode root,int kk){
    
    
    	//只要是找不到都返回-1,所以只要返回了非-1得数据就说明是找到了,一路返回到根节点
        if(root == null) return -1;
        int r = inorder(root.right,kk);
        if(r != -1) return r;
        
        if(num == kk) return root.val;
        else num++;

        int l = inorder(root.left,kk);
        if(l != -1) return l;
        return -1;
    }
    public int kthLargest(TreeNode root, int k) {
    
    
        num = 1;
        return inorder(root,k);
    }
}

最终耗时也是 0 ms

543. 二叉树的直径

使用一个 maxDepth 方法计算某棵子树中经过根节点的最长路径的长度并返回这棵子树的深度,使用 res 维护计算过程中遇到的所有路径长度中的最大值,最后返回 res 即可

class Solution {
    
    
    int res;
    public int diameterOfBinaryTree(TreeNode root) {
    
    
        maxDepth(root);
        return res;
    }
    public int maxDepth(TreeNode root) {
    
    
        if(root == null) return 0;
        int leftDepth = maxDepth(root.left);        //计算左子树深度
        int rightDepth = maxDepth(root.right);      //计算右子树深度
        res = Math.max(res,leftDepth + rightDepth); //计算经过根节点最长路径长度
        return 1 + Math.max(leftDepth,rightDepth);  //返回当前树的深度
    }
}

110.平衡二叉树

一开始想用 104 题中求深度的方法,从根开始遍历每个结点,然后求每个节点的左右子树的深度,然后判断是否平衡,但其实对于每一个结点,求他的子树的深度时都需要往下递归直到节点为空,这样中间会做很多多余的计算

问题就在于,如果整棵树存在不平衡的子树,在递归求所有节点的左右子树深度时一定会找到某个节点左右子树高度相差大于 1,这时已经可以判断是不平衡的二叉树了,而这个结论在递归计算过程中没有被保留下来

 class Solution {
    
    
    public int depth(TreeNode root){
    
    
        if(root == null) return 0;
        int left = depth(root.left);
        //如果左右子树的执行结果已经是-1,说明左右子树已经出现了不平衡的情况,那整棵子树也肯定不平衡
        if(left == -1) return -1;
        int right = depth(root.right);
        if(right == -1) return -1;
        //判断是否平衡
        if(Math.abs(left - right) > 1) return -1;
        //不平衡就正常返回当前节点(为根的子树)的深度
        return Math.max(left,right) + 1;
    }
    public boolean isBalanced(TreeNode root) {
    
    
        if(depth(root) == -1) return false;
        return true;
    }
}

面试题 04.04. 检查平衡性

检查平衡性,就是要通过左右子树的高度差来判断,所以思路就是求深度,但又不需要对每个节点都去求深度,只要找到一个高度差大于 1,就可以得出整棵树是不平衡的结论了

class Solution {
    
    
    int depth(TreeNode t){
    
    
        if(t == null) return 0;
        int l = depth(t.left);
        if(l == -1) return -1;   //----|
        int r = depth(t.right);  //    |-->左右子树有一个返回了-1,根节点就可以直接返回-1
        if(r == -1) return -1;   //----|
        if(Math.abs(l - r) > 1) return -1; //当前根节点的子树不平衡,返回-1
        return Math.max(l,r) + 1;          //当前子树是平衡的,就返回深度
        //可以看出来,只要找到了一个高度差大于1,返回值-1就会一直沿着节点往上一直返回到最上面根节点,避免了其它求深度的操作
    }
    public boolean isBalanced(TreeNode root) {
    
    
        if(depth(root) == -1) return false;
        return true;
    }
}

猜你喜欢

转载自blog.csdn.net/Pacifica_/article/details/125765313