力扣刷题笔记 二叉树&二叉搜索树

二叉树

二叉树的题目时的通用思考过程是:
1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现。
2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值。
3、无论使用哪一种思维模式,你都要明白二叉树的每一个节点需要做什么,需要在什么时候(前中后序)做

基础篇

104. 二叉树的最大深度
// 定义:输入根节点,返回这棵二叉树的最大深度
int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    // 利用定义,计算左右子树的最大深度
    int leftMax = maxDepth(root.left);
    int rightMax = maxDepth(root.right);
    // 整棵树的最大深度等于左右子树的最大深度取最大值,
    // 然后再加上根节点自己
    int res = Math.max(leftMax, rightMax) + 1;
    
    return res;
}
// 记录最大深度
int res = 0;
// 记录遍历到的节点的深度
int depth = 0;

// 主函数
int maxDepth(TreeNode root) {
	traverse(root);
	return res;
}

// 二叉树遍历框架
void traverse(TreeNode root) {
	if (root == null) {
		// 到达叶子节点,更新最大深度
		res = Math.max(res, depth);
		return;
	}
	// 前序位置
	depth++;
	traverse(root.left);
	traverse(root.right);
	// 后序位置
	depth--;
}
543. 二叉树的直径

解决这题的关键在于,每一条二叉树的「直径」长度,就是一个节点的左右子树的最大深度之和
法一:

/**
 * 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 maxK = 0;
    public int diameterOfBinaryTree(TreeNode root) {
         // 对每个节点计算直径,求最大直径
        traverse(root);
        return maxK;
    }

    public void traverse(TreeNode root){
        if(root == null){
            return;
        }
         // 对每个节点计算直径
        int maxL = MaxDepth(root.left);
        int maxR = MaxDepth(root.right);
        
        // 更新全局最大直径
        maxK = Math.max(maxK,maxL+maxR);

        traverse(root.left);
        traverse(root.right);

    }
    
    // 计算二叉树的最大深度
    public int MaxDepth(TreeNode root){
        if(root == null){
            return 0;
        }

        int maxLeft = MaxDepth(root.left);
        int maxRight = MaxDepth(root.right);

        return Math.max(maxLeft,maxRight) +1;
    }


}

法二:

class Solution {
    // 记录最大直径的长度
    int maxDiameter  = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        MaxDepth(root);
        return maxDiameter ;
    }

    public int MaxDepth(TreeNode root){
        if(root == null){
            return 0;
        }

        int maxLeft = MaxDepth(root.left);
        int maxRight = MaxDepth(root.right);
        
        // 后序位置,顺便计算最大直径
        maxDiameter  = Math.max(maxDiameter , maxLeft + maxRight);

        return Math.max(maxLeft,maxRight) +1;
    }


}
144. 二叉树的前序遍历
/**
 * 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> arrays = new ArrayList<Integer>();

    public List<Integer> preorderTraversal(TreeNode root) {
        travers(root);
        return arrays;
    }

    public void travers(TreeNode root){
        if (root == null) {
            return;
        }
        arrays.add(root.val);
        preorderTraversal(root.left);
        preorderTraversal(root.right);
    }
}
二叉树的层次遍历
// 输入一棵二叉树的根节点,层序遍历这棵二叉树
void levelTraverse(TreeNode root) {
    if (root == null) return;
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);

    // 从上到下遍历二叉树的每一层
    while (!q.isEmpty()) {
        int sz = q.size();
        // 从左到右遍历每一层的每个节点
        for (int i = 0; i < sz; i++) {
            TreeNode cur = q.poll();
            // 将下一层节点放入队列
            if (cur.left != null) {
                q.offer(cur.left);
            }
            if (cur.right != null) {
                q.offer(cur.right);
            }
        }
    }
}

剑指 Offer 32 - III. 从上到下打印二叉树 III
// 队列 + 栈
class Solution {
    List<List<Integer>> list = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        leveReserse(root);
        return list;
    }

    public void leveReserse(TreeNode root){
        if (root == null){
            return;
        }
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        
        int x =1;
        while(!q.isEmpty()){
            int size = q.size();
            Stack<Integer> st = new Stack<>();
            List<Integer> temp = new ArrayList<>();

            for(int i=0;i<size;i++){
                TreeNode cur = q.poll();
                if(x%2 == 0){
                    st.push(cur.val);
                }else{
                    temp.add(cur.val);
                }
                
                if(cur.left != null){
                    q.offer(cur.left);
                }

                if(cur.right != null){
                    q.offer(cur.right);
                }
            }
            if(x%2 == 0){
                for(int i = 0;i < size;i++){
                    temp.add(st.pop());
                }
            }
            list.add(temp);
            x++;
        }
    }

}
// 参考代码,使用 队列 + 双端队列
// Java 中将链表 LinkedList 作为双端队列使用。
class Solution {
    List<List<Integer>> list = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        leveReserse(root);
        return list;
    }

    public void leveReserse(TreeNode root){
        if (root == null){
            return;
        }
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        
         boolean flag = true;
        while(!q.isEmpty()){
            int size = q.size();
            LinkedList<Integer> temp = new LinkedList<>();
           
            for(int i=0;i<size;i++){
                TreeNode cur = q.poll();
                if(flag){
                   temp.addLast(cur.val);
                }else{
                    temp.addFirst(cur.val);
                }
                
                if(cur.left != null){
                    q.offer(cur.left);
                }

                if(cur.right != null){
                    q.offer(cur.right);
                }
            }
            list.add(temp);
            flag = !flag;
        }
    }

}
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) {
        traverse(root);
        return root;
    }

    TreeNode temp;

    public void traverse(TreeNode root) {
        if(root == null){
            return;
        }

        temp = root.left;
        root.left = root.right;
        root.right = temp;

        traverse(root.left);
        traverse(root.right);
    }
}
/**
 * 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 {
    // 定义:将以 root 为根的这棵二叉树翻转,返回翻转后的二叉树的根节点
    public TreeNode invertTree(TreeNode root) {
        if(root == null){
            return null;
        }

        // 利用函数定义,先翻转左右子树
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);

        // 然后交换左右子节点
        root.left = right;
        root.right = left;
        
        // 和定义逻辑自恰:以 root 为根的这棵二叉树已经被翻转,返回 root
        return root;
    }
}
114. 二叉树展开为链表
/**
 * 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 void flatten(TreeNode root) {
        if(root == null){
            return;
        }

        flatten(root.left);
        flatten(root.right);

        /**** 后序遍历位置 ****/
        // 1、左右子树已经被拉平成一条链表
        TreeNode left = root.left;
        TreeNode right = root.right;
        
        // 2、将左子树作为右子树
        root.left = null;
        root.right = left;

        // 3、将原先的右子树接到当前右子树的末端
        TreeNode p = root;
        // 把指针移动到最后面
        while (p.right != null) {
            p = p.right;
        }
        p.right = right;
    }
}
116. 填充每个节点的下一个右侧节点指针

在这里插入图片描述

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        if(root == null){
            return null;
        }
        // 遍历「三叉树」,连接相邻节点
        traverse(root.left, root.right);
        return root;
    }

    // 三叉树遍历框架
    public void traverse(Node node1,Node node2){
        if(node1==null || node2==null){
            return;
        }

        // 将传入的两个节点穿起来
        node1.next = node2;

        // 连接相同父节点的两个子节点
        traverse(node1.left,node1.right);
        traverse(node2.left,node2.right);

        // 连接跨越父节点的两个子节点
        traverse(node1.right,node2.left);
    }
}

构造二叉树

二叉树的构造问题一般都是使用「分解问题」的思路:构造整棵树 = 根节点 + 构造左子树 + 构造右子树

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 {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return build(nums,0,nums.length-1);
    }

    // 定义:将 nums[lo..hi] 构造成符合条件的树,返回根节点
    public TreeNode build(int[] nums, int low, int high) {
        if (low > high){
            return null;
        }

        // 找到数组中的最大值和对应的索引
        int index = 0,maxVal = Integer.MIN_VALUE;
        for (int i = low ; i <= high ; i++){
            if(nums[i] > maxVal){
                maxVal = nums[i];
                index = i;
            }
        }

        // 先构造出根节点
        TreeNode root = new TreeNode(maxVal);
        // 递归调用构造左右子树
        root.left = build(nums, low, index - 1);
        root.right = build(nums, index + 1, high);

        return root;
    }
}
105. 从前序与中序遍历序列构造二叉树

图片.png

/**
 * 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 {

    // 存储 inorder 中值到索引的映射
    HashMap<Integer,Integer> valIndex = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i = 0 ; i < inorder.length ; i++){
            valIndex.put(inorder[i],i);
        }

        return build(preorder , 0 , preorder.length-1 , 
                     inorder, 0, inorder.length-1);
    }



    public TreeNode build(int[] preorder,int preStart,int preEnd,
    int[] inorder ,int inStart ,int inEnd){
        if(preStart > preEnd){
            return null;
        }

        // root 节点对应的值为前序遍历的第一个元素
        int rootVal = preorder[preStart];
        // rootVal 在中序遍历中的索引
        int index = valIndex.get(rootVal);

        int leftSize = index - inStart;
        
        // 先构造出当前根节点
        TreeNode root =  new TreeNode(rootVal);

        // 递归构造左右子树
        root.left = build(preorder,preStart + 1 ,preStart + leftSize ,
        inorder,inStart,index -1);

        root.right = build(preorder,preStart + leftSize + 1,preEnd,
        inorder,index + 1,inEnd); 

        return root;
    }
}
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 {

    // 存储 inorder 中值到索引的映射
    HashMap<Integer,Integer> valIndex = new HashMap<>();

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i = 0 ; i < inorder.length ; i++){
            valIndex.put(inorder[i],i);
        }
        
        return build(inorder,0,inorder.length - 1,postorder,0,postorder.length - 1);
    }


/* 
    build 函数的定义:
    后序遍历数组为 postorder[postStart..postEnd],
    中序遍历数组为 inorder[inStart..inEnd],
    构造二叉树,返回该二叉树的根节点 
*/
    public TreeNode build(int[] inorder,int inStart,int inEnd,int[] postorder,int posStart,int posEnd){

        if (inStart > inEnd){
            return null;
        }

        // root 节点对应的值就是后序遍历数组的最后一个元素
        int rootVal = postorder[posEnd];

        // rootVal 在中序遍历中的索引
        int index = valIndex.get(rootVal);

        int leftSize = index - inStart;

        TreeNode root  = new TreeNode(rootVal);

         // 递归构造左右子树
        root.left = build(inorder,inStart,index-1,
        postorder,posStart,posStart+leftSize - 1);

        root.right = build(inorder,index+1,inEnd,
        postorder,posStart + leftSize,posEnd - 1);

        return root;
    }
}
889. 根据前序和后序遍历构造二叉树

通过前序中序,或者后序中序遍历结果可以确定一棵原始二叉树,但是通过前序后序遍历结果无法确定原始二叉树

1、首先把前序遍历结果的第一个元素或者后序遍历结果的最后一个元素确定为根节点的值
2、然后把前序遍历结果的第二个元素作为左子树的根节点的值
3、在后序遍历结果中寻找左子树根节点的值,从而确定了左子树的索引边界,进而确定右子树的索引边界,递归构造左右子树即可
图片.png

/**
 * 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 {

    HashMap<Integer,Integer> valIndex = new HashMap<>();
    
    public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
        for(int i = 0 ;i < postorder.length; i++){
            valIndex.put(postorder[i],i);
        }

        return build(preorder,0,preorder.length - 1,postorder,0,postorder.length - 1);
    }

    public TreeNode build(int[] preorder,int preStart,int preEnd,int[]postorder ,int postStart,int postEnd){
        if(preStart > preEnd){
            return null;
        }

        if (preStart == preEnd) {
           return new TreeNode(preorder[preStart]);
        }

        // root 节点对应的值就是前序遍历数组的第一个元素
        int rootVal = preorder[preStart];

         // root.left 的值是前序遍历第二个元素
        // 通过前序和后序遍历构造二叉树的关键在于通过左子树的根节点
        // 确定 preorder 和 postorder 中左右子树的元素区间
        int leftRootVal = preorder[preStart + 1];
        // leftRootVal 在后序遍历数组中的索引

        int index = valIndex.get(leftRootVal);

        // 左子树的元素个数
        int leftSize = index - postStart + 1;

        // 先构造出当前根节点
        TreeNode root = new TreeNode(rootVal);

        // 递归构造左右子树
        // 根据左子树的根节点索引和元素个数推导左右子树的索引边界
        root.left = build(preorder,preStart+1,preStart+leftSize,
        postorder,postStart,index);

        root.right = build(preorder,preStart+leftSize+1,preEnd,
        postorder,index+1,preEnd -1);

        return root;
    }
}

二叉树的后序遍历

652. 寻找重复的子树

题解

/**
 * 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 {
    // 记录所有子树以及出现的次数
    HashMap<String,Integer> memo = new HashMap<>();
    // 记录重复的子树根节点
    LinkedList<TreeNode> res = new LinkedList<>();

    LinkedList<TreeNode> res2 = new LinkedList<>();


    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        traverse(root);

        int length = res.size();
        for(int i = (length - 1);i >= 0;i--){
            res2.add(res.get(i));
        }
        return res2;
    }

    public String traverse(TreeNode root){
        if(root == null){
            return "#";
        }

        String left = traverse(root.left);
        String right = traverse(root.right);

        String subTree = left+","+right+","+root.val;

        int freq = memo.getOrDefault(subTree,0);
        // 多次重复也只会被加入结果一次
        if(freq == 1){
            res.add(root);
        }
        // 给子树对应的出现次数
        memo.put(subTree,freq+1);
        return subTree;
    }
}
1373. 二叉搜索子树的最大键值和(困难)

计算⼦树中 BST 的最⼤和,站在当前节点的视⻆,需要做什么呢?
1、我肯定得知道左右⼦树是不是合法的 BST,如果这俩⼉⼦有⼀个不是 BST,以我为根的这棵树肯定不会是 BST,对吧。
2、如果左右⼦树都是合法的 BST,我得瞅瞅左右⼦树加上⾃⼰还是不是合法的 BST 了。因为按照 BST 的定 义,当前节点的值应该⼤于左⼦树的最⼤值,⼩于右⼦树的最⼩值,否则就破坏了 BST 的性质。
3、因为题⽬要计算最⼤的节点之和,如果左右⼦树加上我⾃⼰还是⼀棵合法的 BST,也就是说以我为根的 整棵树是⼀棵 BST,那我需要知道我们这棵 BST 的所有节点值之和是多少,⽅便和别的 BST 争个⾼下,对 吧。

根据以上三点,站在当前节点的视⻆,需要知道以下具体信息:
1、左右⼦树是否是 BST。
2、左⼦树的最⼤值和右⼦树的最⼩值。
3、左右⼦树的节点值之和。

/**
 * 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 {
    // 全局变量,记录 BST 最大节点之和
    int maxSum = 0;
    public int maxSumBST(TreeNode root) {
        traverse(root);
        return maxSum;
    }

    public int[] traverse(TreeNode root){
        if(root == null){
            return new int[]{
                1,Integer.MAX_VALUE,Integer.MIN_VALUE,0
            };
        }

        // 递归计算左右二叉树
        int[] left = traverse(root.left);
        int[] right = traverse(root.right);

        int[] res = new int[4];
        /* 后序遍历位置  */
        // 判断以root为根的二叉树是不是 BST
        if(left[0] == 1 && right[0] == 1 && left[2] < root.val && right[1] > root.val){
            // 以root为根的二叉树是BST
            res[0] = 1;
            // 计算以 root 为根的这棵 BST 的最小值
            res[1] = Math.min(left[1],root.val);
            // 计算以 root 为根的这棵 BST 的最大值
            res[2] = Math.max(right[2],root.val);
            // 计算以 root 为根的这棵 BST 所有节点之和
            res[3] = left[3] + root.val +right[3];

            // 更新全局变量
            maxSum = Math.max(maxSum,res[3]); 
        }else{
            res[0] = 0;
            // 其它值不用计算,用不到。
        }
        return res;
    }
}

⼆叉树的序列化

297. 二叉树的序列化与反序列化

解法讲解

前序遍历解法
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    String SEP = ",";
    String NULL = "#";
    // 主函数,将二叉树序列化为字符串 
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        serializeHelp(root,sb);
        return sb.toString();
    }

    // 辅助函数,将二叉树存入 StringBuilder
    public void serializeHelp(TreeNode root,StringBuilder sb){
        if(root == null){
            sb.append(NULL).append(SEP);
            return;
        }
        
        // 前序遍历位置 
        sb.append(root.val).append(SEP);
        
        serializeHelp(root.left, sb);
        serializeHelp(root.right, sb);
    }

    // 主函数,将字符串反序列化为二叉树结构
    public TreeNode deserialize(String data) {
        // 将字符串转化成列表
        LinkedList<String> nodes = new LinkedList<>();
        for (String s : data.split(SEP)) {
            nodes.addLast(s);
        }
        return deserializeHelp(nodes);
    }

    // 通过 nodes 列表构造二叉树
    public TreeNode deserializeHelp(LinkedList<String> nodes){
        if(nodes.isEmpty()){
            return null;
        }
        // 列表最左侧就是根节点
        String first = nodes.removeFirst();
        if(first.equals(NULL)){
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(first));

        root.left = deserializeHelp(nodes);
        root.right = deserializeHelp(nodes);

        return root;        
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));
后序遍历解法
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    String SEP = ",";
    String NULL = "#";
    // 主函数,将二叉树序列化为字符串 
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        serializeHelp(root,sb);
        return sb.toString();
    }

    // 辅助函数,将二叉树存入 StringBuilder
    public void serializeHelp(TreeNode root,StringBuilder sb){
        if(root == null){
            sb.append(NULL).append(SEP);
            return;
        }
        
        serializeHelp(root.left, sb);
        serializeHelp(root.right, sb);

        // 后序遍历位置 
        sb.append(root.val).append(SEP);
    }

    // 主函数,将字符串反序列化为二叉树结构
    public TreeNode deserialize(String data) {
        // 将字符串转化成列表
        LinkedList<String> nodes = new LinkedList<>();
        for (String s : data.split(SEP)) {
            nodes.addLast(s);
        }
        return deserializeHelp(nodes);
    }

    // 通过 nodes 列表构造二叉树
    public TreeNode deserializeHelp(LinkedList<String> nodes){
        if(nodes.isEmpty()){
            return null;
        }
        // 从后往前取出元素
        String last = nodes.removeLast();

        if(last.equals(NULL)){
            return null;
        }

        TreeNode root = new TreeNode(Integer.parseInt(last));

        /*
        因为从后往前在 nodes 列表中取元素,一定要先构造 root.right 子树,
        后构造 root.left 子树
        */
        root.right = deserializeHelp(nodes);
        root.left = deserializeHelp(nodes);
        

        return root;        
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));
中序遍历解法

只能序列化,不能反序列化

/* 辅助函数,将二叉树存入 StringBuilder */
void serializeHelp(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    serialize(root.left, sb);
    /****** 中序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/
    serialize(root.right, sb);
}
层级遍历解法
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    String SEP = ",";
    String NULL = "#";
    // 主函数,将二叉树序列化为字符串 
    public String serialize(TreeNode root) {
        if (root == null){
            return "";
        } 
        StringBuilder sb = new StringBuilder();
        // 初始化队列,将 root 加入队列
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()) {
            TreeNode cur = q.poll();

            /* 层级遍历代码位置 */
            if (cur == null) {
                sb.append(NULL).append(SEP);
                continue;
            }
            sb.append(cur.val).append(SEP);
            /*****************/

            q.offer(cur.left);
            q.offer(cur.right);
        }

        return sb.toString();
    }

    // 主函数,将字符串反序列化为二叉树结构
    public TreeNode deserialize(String data) {
        if (data.isEmpty()){
            return null;
        } 
        String[] nodes = data.split(SEP);
        // 第一个元素就是 root 的值
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));

        // 队列 q 记录父节点,将 root 加入队列
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        for (int i = 1; i < nodes.length; ) {
            // 队列中存的都是父节点
            TreeNode parent = q.poll();
            // 父节点对应的左侧子节点的值
            String left = nodes[i++];
            if (!left.equals(NULL)) {
                parent.left = new TreeNode(Integer.parseInt(left));
                q.offer(parent.left);
            } else {
                parent.left = null;
            }
            // 父节点对应的右侧子节点的值
            String right = nodes[i++];
            if (!right.equals(NULL)) {
                parent.right = new TreeNode(Integer.parseInt(right));
                q.offer(parent.right);
            } else {
                parent.right = null;
            }
        }
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

其他

剑指 Offer 26. 树的子结构

–>题解

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        return (A != null && B != null) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));
    }
    public boolean recur(TreeNode A, TreeNode B) {
        if(B == null) return true;
        if(A == null || A.val != B.val) return false;
        return recur(A.left, B.left) && recur(A.right, B.right);
    }
}

二叉搜索树

BST 的特性:
1、对于 BST 的每一个节点 node,左子树节点的值都比 node 的值要小,右子树节点的值都比 node 的值大。
2、对于 BST 的每一个节点 node,它的左侧子树和右侧子树都是 BST。
重要的性质:BST 的中序遍历结果是有序的(升序)

基础篇

230. 二叉搜索树中第K小的元素
/**
 * 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 kthSmallest(TreeNode root, int k) {
        teaverse(root,k);
        return res;
    }
    // 记录结果
    int res = 0;
    // 记录当前元素的排名
    int rank = 0;
    public void teaverse(TreeNode root,int k){
        if(root == null){
            return;
        }

        teaverse(root.left,k);
        /* 中序遍历代码位置 */
        rank++;
        if(k == rank){
            // 找到第 k 小的元素
            res = root.val;
            return;
        }

        teaverse(root.right,k);
    }
}
538. 把二叉搜索树转换为累加树
1038. 从二叉搜索树到更大和树

两道题完全相同

/**
 * 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 convertBST(TreeNode root) {
        traverse(root);
        return root;
    }

    // 记录累加和
    int  sum = 0;
    public void traverse(TreeNode root){
        if(root == null){
            return;
        }

        traverse(root.right);

        sum += root.val;
        root.val = sum;

        traverse(root.left);

    }
}

基本操作篇

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  isValidBST(root,null,null);
    }

/* 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val */
    public boolean isValidBST(TreeNode root,TreeNode min,TreeNode max) {
        if(root == null){
            return true;
        }
        // 若 root.val 不符合 max 和 min 的限制,说明不是合法 BST
        if(min != null && root.val <= min.val){
            return false;
        }
        if(max != null && root.val >= max.val){
            return false;
        }
        // 限定左子树的最大值是 root.val,右子树的最小值是 root.val
        return isValidBST(root.left,min,root) && isValidBST(root.right,root,max);
    }
}
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) {
        return traverse(root,val);
    }

    public TreeNode traverse(TreeNode root,int val){
        if(root == null){
            return null;
        }

        // 去左子树搜索
        if(root.val > val){
            return traverse(root.left,val);
        }

        // 去右子树搜索
        if(root.val < val){
            return traverse(root.right,val);
        }
        return root;
    }
}
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);
        }

        if(root.val < val){
            root.right = insertIntoBST(root.right ,val);
        }

        return root;
    }
}

Study
labuladong算法小抄

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值