二叉树相关算法题目总结

二叉树基础

二叉树本身是一个每个节点最多包含左右两个节点的树。

对于二叉树来讲,不像其他集合(List,Map)之类的有已经造好的轮子直接拿来用。所以多数场景下,遇到二叉树,需要我们自己来定义二叉树的数据结构。

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(int val) {
        this.val = val;
    }
}

二叉树的遍历

二叉树最常用的就是对本身的遍历。就像遍历一个集合一样,遍历二叉树最常用的就是前中后序遍历

前序遍历

    private static void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        dfs(root.left);
        dfs(root.right);
    }

中序遍历

    private static void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        dfs(root.left);
        System.out.print(root.val + " ");
        dfs(root.right);
    }

后序遍历

    private static void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        dfs(root.left);
        dfs(root.right);
        System.out.print(root.val + " ");
    }

二叉树常见题型

就像学习其他集合一样,了解了结合的概念和遍历方式之后,剩下的就是对于集合各种各样的操作。下面通过几种题目来熟悉下二叉树的几种操作。

对二叉树的每个值加1

    private static void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + 1 + " ");
        dfs(root.left);
        dfs(root.right);
    }

这个很简单,就是在二叉树前序遍历的基础上对自身的值+1之后再打印

判断两棵二叉树是否完全相同

    private static boolean judge(TreeNode node1, TreeNode node2) {
        if (node1 == null && node2 == null) {
            return true;
        }
        if (node1 == null || node2 == null) {
            return false;
        }
        if (node1.val != node2.val) {
            return false;
        }
        return judge(node1.left, node2.left) && judge(node1.right, node2.right);
    }

这个题目稍稍有一点儿难度,但是不难观察,题目本身依旧是对二叉树的遍历。只是在遍历之前要对当前节点做判断,先确认两个二叉树的当前节点都不为空,否则的话任何一个节点为空都能确认两个二叉树不相等,前两个条件都执行过之后,再确认当前两个节点的值相同。经过这三步判断,就能确认当前两个节点是相同的,再继续遍历,直到遍历结束,返回最终的结果值。

搜索二叉树(BST)

下面我们说一种特殊的二叉树--搜索二叉树(BST)

搜索二叉树需要满足当前节点大于所有左节点,并且当前节点小于所有右节点。符合以上条件的二叉树就是搜索二叉树。

基于这种数据结构,我们看几道相关的题目

判断BST的合法性

    private boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) {
        if (root == null) {
            return true;
        }
        if (min != null && root.val <= min.val) {
            return false;
        }
        if (max != null && root.val >= max.val) {
            return false;
        }
        return isValidBST(root.left, min, root) && isValidBST(root.right, root, max);
    }

这里,我们在二叉树前序遍历的基础上,多传了min和max两个参数,目的是避免类似于右节点的子节点大于其父节点的情况。

二叉树相关算法题目总结_第1张图片

基于上述几道题目,细心的同学其实可以总结发现一个规律,涉及二叉树的题目是可以套用一种模板的,就是先判断当前节点是否符合条件,再分别判断左右节点是否符合条件。

void traverse(TreeNode root) {
    // root 需要做什么?在这做。
    // 其他的不用 root 操心,抛给框架
    traverse(root.left);
    traverse(root.right);
}

既然框架有了,我们再看下面几道题

在二叉树中插入一个值

    private TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) {
            return new TreeNode(val);
        }
        if (root.val < val) {
            root.right = insertIntoBST(root.right, val);
        }
        if (root.val > val) {
            root.left = insertIntoBST(root.left, val);
        }
        return root;
    }

套用模板,先对当前节点进行处理,然后分别处理其左右节点。

在二叉搜索树中删除一个值

    private TreeNode deleteBST(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        if (root.val == val) {
            if (root.left == null) {
                return root.right;
            }
            if (root.right == null) {
                return root.left;
            }
            TreeNode minNode = getMinNode(root);
            root.val = minNode.val;
            root.right = deleteBST(root.right, minNode.val);
        }
        if (root.val > val) {
            root.left = deleteBST(root.left, val);
        }
        if (root.val < val) {
            root.right = deleteBST(root.right, val);
        }
        return root;
    }

    private TreeNode getMinNode(TreeNode root) {
        while (root.left != null) {
            root = root.left;
        }
        return root;
    }

还是套用模板,先判断当前节点,然后分别处理其左右节点。但是这道题在删除节点的时候需要注意。在删除的时候,叶子节点可以直接删除,非叶子节点的话,要特殊处理下,这里我们处理的方式是,找到要删除节点的右节点,取到它的子节点的最小值(通过搜索二叉树的特性可知,左节点的值一定比当前节点的值小),将这个最小值的放到山被删除的节点位置上,即完成了删除BST中一个节点的动作。

总结

基于以上二叉树和二叉搜索树相关的题目,我们了解到了二叉树刷题的基本套路,也得到了一个二叉树刷题的模板

void traverse(TreeNode root) {
    // root 需要做什么?在这做。
    // 其他的不用 root 操心,抛给框架
    traverse(root.left);
    traverse(root.right);
}

只要是二叉树相关的题目,大部分都可以往这个模板上套,不同的就是在遍历的时候逻辑关系的处理。

你可能感兴趣的:(leetcode,#,二叉树)