代码随想录打卡-二叉树

目录

一、理论基础

1.1 二叉树的种类

1.2 二叉树的存储方式

1.3 二叉树的遍历方式

1.4 二叉树的定义

二、二叉树的遍历

2.1 深度优先遍历-前中后序

2.1.1 递归法

2.1.2 迭代法

2.2 广度优先遍历-层序遍历

三、求二叉树的属性

3.1 二叉树:是否对称

3.2 二叉树:最大/小深度

3.3 二叉树:求有多少个节点

3.4 二叉树:是否平衡

3.5 找所有的路径

3.6 二叉树:求左叶子之和

3.7 二叉树:求左下角的值

3.8 二叉树:求路径总和

四、二叉树的修改与构造

4.1 翻转二叉树

4.2 构造二叉树

4.2.1 前序与中序构造

4.2.2 中序与后序构造

4.3 构造最大的二叉树

4.4 合并两个二叉树

五、求二叉搜索树的属性

5.1 二叉搜索树中的搜索

5.2 是不是二叉搜索树

5.3 求二叉搜索树的最小绝对差

5.4 求二叉搜索树的众数

5.5 二叉搜索树转成累加树

六、 二叉树公共祖先问题

6.1 二叉树的公共祖先问题

6.2 二叉搜索树的公共祖先问题

七、 二叉搜索树的修改与构造

7.1 二叉搜索树中的插入操作

7.2 二叉搜索树中的删除操作

7.3 修剪二叉搜索树

7.4 构造二叉搜索树

八、 总结


一、理论基础

1.1 二叉树的种类

满二叉树:一颗二叉树上只有度为0的节点和度为2的节点,并且度为0的节点都在同一层上

完全二叉树:若二叉树的深度为h,除第h层外,其它各层的节点数都达到最大值,第h层所有的节点都连续集中在最左边

完全二叉树判断方法:叶节点只能出现在最下层和次下层,并且最下面一层的节点都集中在最左边的若干位置

二叉搜索树:若左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值大于它的根节点的值。它的左右子树也分别为二叉排序树

平衡二叉搜索树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树

1.2 二叉树的存储方式

链式存储:用指针

顺序存储:用数组

1.3 二叉树的遍历方式

1、深度优先遍历(DFS):先往深走,遇到叶子节点再往回走(前中后序遍历)

2、广度优先遍历(BFS):一层一层地去遍历(层次遍历)

前序遍历:中左右

中序遍历:左中右

后序遍历:左右中

1.4 二叉树的定义

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;
    }
}

二、二叉树的遍历

2.1 深度优先遍历-前中后序

2.1.1 递归法

递归三要素:

1、确定递归函数的参数和返回值

2、确定终止条件

3、确定单层递归的逻辑

144.二叉树的前序遍历

94.二叉树的中序遍历

145.二叉树的后序遍历

/**
 * 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 {
    List<Integer> res;
    public List<Integer> preorderTraversal(TreeNode root) {
        //方法一:递归
        res = new ArrayList<>();
        preorder(root);
        return res;
    }
    //注意返回值和参数
    private void preorder(TreeNode root){
        //终止条件:节点为空
        if(root==null){
            return;
        }
        //前序:中左右
        //单层递归的逻辑
        res.add(root.val);
        preorder(root.left);
        preorder(root.right);
    }
}

2.1.2 迭代法

利用来实现(先进后出LIFO)

前序:中左右

根据栈先进后出的性质,出来时是左右,则进栈时应该是右左

/**
 * 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 List<Integer> preorderTraversal(TreeNode root) {
        //方法二:迭代法
        //前序:中左右
        //无论怎样,中间的节点都是先拎出来处理的,而根据栈先入后出的特点,要想出来后是中左右,进去的时候就应该是中右左
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> res = new ArrayList<>();
        if(root==null){
            return res;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode tmpNode = stack.pop();
            res.add(tmpNode.val);
            if(tmpNode.right!=null){
                stack.push(tmpNode.right);
            }
            if(tmpNode.left!=null){
                stack.push(tmpNode.left);
            }
        }
        return res;
    }
}

后序其实就是在前序的基础上修改

后序:左右中

翻转过来就是中右左,和前序的区别就是左右换个顺序 

/**
 * 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 List<Integer> postorderTraversal(TreeNode root) {
        //后序:左右中
        //相当于先求 中右左,就是前序的左右换位置
        //最后再翻转
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root==null){
            return res;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode tmpNode = stack.pop();
            res.add(tmpNode.val);
            if(tmpNode.left!=null){
                stack.push(tmpNode.left);
            }
            if(tmpNode.right!=null){
                stack.push(tmpNode.right);
            }
        }
        //对list集合进行逆序,使用Collections.reverse()方法
        Collections.reverse(res);
        return res;
    }
}

中序遍历使用迭代法与前后序不同的原因在于,此时访问的节点和要处理的节点不是同一个

先不断向左找到要访问的节点,再通过栈去取出要处理的节点

/**
 * 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 List<Integer> inorderTraversal(TreeNode root) {
        //方法二:迭代法
        //与前后序思路不同
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root==null){
            return res;
        }
        TreeNode cur = root;
        while(cur!=null || !stack.isEmpty()){
            if(cur!=null){
                stack.push(cur);
                cur = cur.left;
            }else{
                cur = stack.pop();
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }
}

2.2 广度优先遍历-层序遍历

利用队列(先进先出)来实现层序遍历

层序遍历练习题

三、求二叉树的属性

3.1 二叉树:是否对称

101.对称二叉树

方法:递归【后序】

/**
 * 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 isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return compare(root.left,root.right);
    }

    private boolean compare(TreeNode left,TreeNode right){
        if(left==null && right!=null){
            return false;
        }
        if(left==null || right==null){
            return false;
        }
        if(left.val!=right.val){
            return false;
        }

        //对比外侧
        boolean out = compare(left.left,right.right);
        //对比内侧
        boolean in = compare(left.right,right.left);
        //均要true才true
        return out&&in;
    }
}

3.2 二叉树:最大/小深度

方法一:迭代法(不做详细说明,利用队列实现,和前面迭代大同小异)

方法二:递归法【后序】

104.二叉树的最大深度

/**
 * 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 int maxDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        int left = maxDepth(root.left);
        int right =maxDepth(root.right);
        return Math.max(left,right)+1;
            }
}

111.二叉树的最小深度

最小深度:从根节点到最近叶子节点的最短路径上的节点数量

/**
 * 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 int minDepth(TreeNode root) {
        if(root==null){
            return 0;
        }

        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);

        if(root.left==null){
            return rightDepth+1;
        }
        if(root.right==null){
            return leftDepth+1;
        }
        //左右节点均不为空
        return Math.min(leftDepth,rightDepth)+1;
    }
}

3.3 二叉树:求有多少个节点

222.完全二叉树的节点个数

迭代法:略

递归法: 

/**
 * 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 int countNodes(TreeNode root) {
        //递归法
        if(root==null){
            return 0;
        }
        int left = countNodes(root.left);
        int right = countNodes(root.right);
        return left+right+1;
    }
}

3.4 二叉树:是否平衡

平衡二叉树:是指该树所有节点的左右子树的深度相差不超过 1

本题使用迭代法会十分繁琐,效率也低,故使用递归法【后序】

110.平衡二叉树

/**
 * 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 isBalanced(TreeNode root) {
        return getHeight(root)!=-1;
    }
    private int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        //先判断是否满足平衡条件,不满足直接返回-1,无需做后面的计算
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        if(leftHeight==-1 || rightHeight==-1){
            return -1;
        }

        if(Math.abs(leftHeight-rightHeight)>1){
            return -1;
        }

        //返回树的高度
        return Math.max(leftHeight,rightHeight)+1;
        
    }
}

3.5 找所有的路径

递归【前序】+回溯

257.二叉树的所有路径

/**
 * 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 {
    List<String> res;
    List<TreeNode> paths;
    public List<String> binaryTreePaths(TreeNode root) {
        //递归+回溯
        res = new ArrayList<>();
        paths = new ArrayList<>();
        
        getPaths(root);
        return res;
    }
    private void getPaths(TreeNode root){
        if(root==null){
            return;
        }
        //前序遍历
        paths.add(root);
        
        //如果当前是叶子节点
        if(root.left==null && root.right==null){
            StringBuilder sb = new StringBuilder();
        for(int i = 0;i<paths.size()-1;i++){
            sb.append(paths.get(i).val).append("->");
        }
        sb.append(paths.get(paths.size()-1).val);
        res.add(sb.toString());
        }
        
        if(root.left!=null){
            getPaths(root.left);
            paths.remove(paths.size()-1);
        }
        if(root.right!=null){
            getPaths(root.right);
            paths.remove(paths.size()-1);
        }
    }
}

3.6 二叉树:求左叶子之和

404.左叶子之和

递归法

/**
 * 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 {
    //注意:本题容易遗漏的信息-叶子节点!
    int sum;
    public int sumOfLeftLeaves(TreeNode root) {
        sum = 0;
        getSum(root);
        return sum;
        
    }
    private void getSum(TreeNode root){
        if(root==null){
            return;
        }
        if(root.left!=null){
            if(root.left.left==null && root.left.right==null){
                sum += root.left.val;
            }
        }
        getSum(root.left);
        getSum(root.right);
    }
}

3.7 二叉树:求左下角的值

513.找树左下角的值

迭代略

3.8 二叉树:求路径总和

112.路径总和

递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树

有返回值:找到一个true就返回,而不用搜整棵树 

/**
 * 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 hasPathSum(TreeNode root, int targetSum) {
        
        return caculateSum(root,targetSum);
    }
    private boolean caculateSum(TreeNode root,int targetSum){
        //前序遍历
        if(root==null){
            return false;
        }
        targetSum -= root.val;
        if(root.left==null && root.right==null){
            if(targetSum==0){
                return true;
            }
            return false;
        }
       return caculateSum(root.left,targetSum) || caculateSum(root.right,targetSum);
    }
}

四、二叉树的修改与构造

4.1 翻转二叉树

226.翻转二叉树

/**
 * 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 invertTree(TreeNode root) {
        //递归
        if(root==null){
            return root;
        }
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

4.2 构造二叉树

4.2.1 前序与中序构造

105. 从前序与中序遍历序列构造二叉树

注意点:

1、记录:索引、创建节点、左边长度

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 {
    Map<Integer,Integer> map;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map = new HashMap<>();
        for(int i = 0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
       return getRoot(preorder,0,preorder.length,inorder,0,inorder.length);
    }
    private TreeNode getRoot(int[] preorder,int preBegin,int preEnd,int[] inorder,int inBegin,int inEnd){
        //左闭右开
        if(preBegin>=preEnd || inBegin>=inEnd){
            return null;
        }
       
        //记录父节点的索引位置
        int nodeIndex = map.get(preorder[preBegin]);
         //创建节点
        TreeNode root = new TreeNode(inorder[nodeIndex]);
        //记录左边的长度
        int lenOfLeft = nodeIndex-inBegin;
        root.left = getRoot(preorder,preBegin+1,preBegin+1+lenOfLeft,inorder,inBegin,nodeIndex);
        root.right = getRoot(preorder,preBegin+1+lenOfLeft,preEnd,inorder,nodeIndex+1,inEnd);
        return root;
    }
}

4.2.2 中序与后序构造

106. 从中序与后序遍历序列构造二叉树

/**
 * 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 {
    Map<Integer,Integer> map;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map = new HashMap<>();
        for(int i = 0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
       return getRoot(inorder,0,inorder.length,postorder,0,postorder.length);
    }
    private TreeNode getRoot(int[] inorder,int inBegin,int inEnd, int[] postorder,int postBegin,int postEnd){
        if(inBegin>=inEnd || postBegin>=postEnd){
            return null;
        }
        int nodeIndex = map.get(postorder[postEnd-1]);
        TreeNode root = new TreeNode(inorder[nodeIndex]);
        int lenOfLeft = nodeIndex-inBegin;
        root.left = getRoot(inorder,inBegin,nodeIndex,postorder,postBegin,postBegin+lenOfLeft);
        root.right = getRoot(inorder,nodeIndex+1,inEnd,postorder,postBegin+lenOfLeft,postEnd-1);
        return root;
    }
}

4.3 构造最大的二叉树

654.最大二叉树

/**
 * 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 {
    Map<Integer,Integer> map;
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        map = new HashMap<>();
        for(int i = 0;i<nums.length;i++){
            map.put(nums[i],i);
        }
        return getRoot(nums,0,nums.length);
    }

    private TreeNode getRoot(int[] nums,int begin,int end){
        if(begin>=end){
            return null;
        }
        int max = nums[begin];
        for(int i = begin;i<end;i++){
            max = Math.max(max,nums[i]);
        }
        int rootIndex = map.get(max);
        TreeNode root = new TreeNode(max);
        root.left = getRoot(nums,begin,rootIndex);
        root.right = getRoot(nums,rootIndex+1,end);
        return root;
    }
}

4.4 合并两个二叉树

617.合并二叉树

/**
 * 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 && root2==null){
            return null;
        }
        if(root1==null && root2!=null){
            return root2;
        }
        if(root1!=null && root2==null){
            return root1;
        }
        //都不为null
        TreeNode root = new TreeNode(root1.val+root2.val);
        root.left = mergeTrees(root1.left,root2.left);
        root.right = mergeTrees(root1.right,root2.right);
        return root;
    }
}

五、求二叉搜索树的属性

5.1 二叉搜索树中的搜索

700.二叉搜索树中的搜索

迭代法略啦,重点介绍一下递归法

二叉树的递归法都是有方向的

/**
 * 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) {
        //递归法
        if(root==null || root.val==val){
            return root;
        }
        //目标数比节点的数小,则往左子树找,反之找右子树
        if(root.val>val){
            return searchBST(root.left,val);
        }else{
            return searchBST(root.right,val);
        }
    }
}

5.2 是不是二叉搜索树

98.验证二叉搜索树

/**
 * 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 validBST(Long.MIN_VALUE,Long.MAX_VALUE,root);
    }

    private boolean validBST(long lower,long upper,TreeNode root){
        if(root==null){
            return true;
        }
        //注意:等于也不行
        if(root.val<=lower || root.val>=upper){
            return false;
        }
        return validBST(lower,root.val,root.left) && validBST(root.val,upper,root.right);
    }
}

5.3 求二叉搜索树的最小绝对差

530.二叉搜索树的最小绝对差

迭代法略

递归法:注意这是一个二叉搜索树,可以看作一个有序数组,求最小差值,那只有可能在两相邻节点

/**
 * 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 {
    int res;
    TreeNode pre;
    public int getMinimumDifference(TreeNode root) {
        res = Integer.MAX_VALUE;
        if(root==null){
            return 0;
        }
        traversal(root);
        return res;
    }

    private void traversal(TreeNode root){
        if(root==null){
            return;
        }
        traversal(root.left);
        if(pre!=null){
            res = Math.min(res,Math.abs(pre.val-root.val));
        }
        pre = root;
        traversal(root.right);
    }
}

5.4 求二叉搜索树的众数

501.二叉搜索树中的众数

/**
 * 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 {
    int maxCount;
    int count;
    List<Integer> list;
    TreeNode pre;

    public int[] findMode(TreeNode root) {
        maxCount = 0;
        count = 0;
        pre = null;
        list = new ArrayList<>();
        findMode1(root);
        int[] res = new int[list.size()];
        for(int i = 0;i<res.length;i++){
            res[i] = list.get(i);
        }
        return res;
    }
    private void findMode1(TreeNode root){
        if(root==null){
            return;
        }

        findMode1(root.left);

        //注意:pre==null不可漏,若限定大条件pre!=null,那么pre==null的情况也会被忽略
            if(pre==null || pre.val!=root.val){
            count=1;
        }else{
            count++;
        }
        if(count>maxCount){
            maxCount = count;
            list.clear();
            list.add(root.val);
        }else if(count==maxCount){
            list.add(root.val);
        }
        pre = root;
        

        findMode1(root.right);
    }
}

5.5 二叉搜索树转成累加树

538.把二叉搜索树转换成累加树

核心:按右中左顺序遍历

/**
 * 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 {
    int sum;
    public TreeNode convertBST(TreeNode root) {
        sum = 0;
        traversal(root);
        return root;
    }

    private void traversal(TreeNode root){
        //右中左
        if(root==null){
            return;
        }
        traversal(root.right);
        sum += root.val;
        root.val = sum;
        traversal(root.left);
    }
}

六、 二叉树公共祖先问题

6.1 二叉树的公共祖先问题

236.二叉树的最近公共祖先

 如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null || root==p || root==q){
            return root;
        }
        //祖先:后序遍历
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left==null && right==null){
            return null;
        }else if(left!=null && right==null){
            return left;
        }else if(left==null && right!=null){
            return right;
        }
        return root;
    }
}

6.2 二叉搜索树的公共祖先问题

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

也可以按一般二叉树去解决,但既然有二叉搜索树的特性,别浪费噜

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //既然是二叉搜索树,那就利用好它右大左小的性质
        //递归法
        
        if(root.val>p.val && root.val>q.val){
            return lowestCommonAncestor(root.left,p,q);
        }else if(root.val<p.val && root.val<q.val){
            return lowestCommonAncestor(root.right,p,q);
        }
        return root;
    }
}

七、 二叉搜索树的修改与构造

7.1 二叉搜索树中的插入操作

701.二叉搜索树中的插入操作

多种方式都可,那么可以不用考虑复杂的改变树的构造

直接遍历二叉树,找到空节点,插入即可

/**
 * 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 insertIntoBST(TreeNode root, int val) {
        //遍历二叉树,找到空节点(末尾节点)插入即可
        if(root==null){
            return new TreeNode(val);
        }
        if(root.val>val){
            //小,往左走
            root.left = insertIntoBST(root.left,val);
        }else if(root.val<val){
            //大,往右走
            root.right = insertIntoBST(root.right,val);
        }
        return root;
    }
}

7.2 二叉搜索树中的删除操作

450.删除二叉搜索树中的节点

步骤:1、找节点

           2、删除节点

情况分析:①找不到节点:返回root

                  ②找到节点:I.该节点“缺一边”:直接返回另一半边树

                                       II.节点左右子树均不为null:将左子树搬到右子树的最左侧(原理:比小的还小,那一定比大的小)

/**
 * 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 deleteNode(TreeNode root, int key) {
        //1、找节点(前序)
        //2、删除节点
        if(root==null){
            return root;
        }
        
        //找到节点了
        if(root.val==key){
            if(root.left==null){
                return root.right;
            }else if(root.right==null){
                return root.left;
            }
            //均不为空
            //左子树移到右子树最左的后面(比小的还小,那一定比大的小)
            TreeNode cur = root.right;//先找到右子树的最左节点
            while(cur.left!=null){
                cur = cur.left;
            }
            cur.left = root.left;//为右子树最左节点的后面赋值,把左子树迁移过去
            return root.right;//注意:此处要把root删了,把左子树已经转移到右子树最左侧了,直接返回右子树即可
        }

        //在处理递归调用时,应该将结果返回给父调用,而不是丢弃它
        if(root.val>key){
            //小,往左找
            root.left = deleteNode(root.left,key);
        }else if(root.val<key){
            //大,往右找
            root.right = deleteNode(root.right,key);
        }
        return root;
    }
}

7.3 修剪二叉搜索树

669.修剪二叉搜索树

步骤:1、找需要修剪的节点

           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 trimBST(TreeNode root, int low, int high) {
        //左闭右闭
        //前序
        if(root==null){
            return root;
        }

        //找到了要删除的节点
        if(root.val > high ){
            //节点都大了,那右子树更是不能要了,所以往左走
            return trimBST(root.left,low,high);
        }else if(root.val < low){
            //同理,节点小了,往右走
            return trimBST(root.right,low,high);
        }

        //没找到,继续递归排查
        root.left = trimBST(root.left,low,high);
        root.right = trimBST(root.right,low,high);
        return root;


    }
}

7.4 构造二叉搜索树

108.将有序数组转换为二叉搜索树

注意特殊的写法以防数组越界

/**
 * 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 sortedArrayToBST(int[] nums) {
        //左闭右开
        return getRoot(nums,0,nums.length);
        
    }
    private TreeNode getRoot(int[] nums,int begin,int end){

        //别漏了最开始验证区间合理的条件!!!
        if(begin>=end){
            return null;
        }
        
        //不使用(begin+end)/2:防止数组越界
        int nodeIndex = begin+(end-begin)/2;
        TreeNode root = new TreeNode(nums[nodeIndex]);

        //注意:升序排列,故index右边是左子树,index左边是右子树
        root.left = getRoot(nums,begin,nodeIndex);
        root.right = getRoot(nums,nodeIndex+1,end);
        return root;
    }
}

八、 总结

1、二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,先构造中节点!

2、求不同二叉树的属性,一般用后序,但还是要具体问题具体分析!

3、求二叉搜索树的属性,用前序,不然白瞎有序性了!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值