代码随想录打卡-二叉树

一、理论基础

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、求二叉搜索树的属性,用前序,不然白瞎有序性了!

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值