二叉树--恢复二叉搜索树

Posted 算法和数据结构

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树--恢复二叉搜索树相关的知识,希望对你有一定的参考价值。

来源:LeetCode

难度:中等

描述:

        给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。


示例1:


示例2:

二叉树(四)--恢复二叉搜索树


分析:

        题意就是原本有一棵好的二叉搜索树,后来其中的两个节点发生了交换,让咱们找到这两个节点并交换回来。

        首先咱们要了解啥是二叉搜索树,所谓的二叉搜索树通俗点讲就是根节点比左节点大,比右节点小的二叉树,因此如果二叉树中节点发生了交换,二叉搜索树整体就不再满足如上特性,而咱们也可以根据这个特性找到交换的节点,将它们交换回来即可

        这里介绍递归和中序遍历两种解法,以下是具体思路和代码解法。


解题


方法一:递归法

思路:我们捋清楚原来的二叉树交换的可能情况有如下几种

  1. 根节点和左子树的某个数字交换 -> 由于正常二叉搜索的根节点大于左子树中的所有节点,所以交换后我们只要找左子树中最大的那个节点,就是所交换的那个节点

  2. 根节点和右子树的某个数字交换 -> 由于根节点小于右子树中的所有节点,所以交换后我们只要在右子树中最小的那个节点,就是所交换的那个节点

  3. 左子树和右子树的两个数字交换 -> 找左子树中最大的节点,右子树中最小的节点,即对应两个交换的数

  4. 左子树中的两个数字交换

  5. 右子树中的两个数字交换

因此我们针对每个节点,找到其左子树最大节点和右子树的最小节点,分为以下情况:

  • 如果左子树最大节点大于根节点,右子树最小节点小于根节点,说明对应情况3

  • 如果左子树最大节点大于根节点,右子树最小节点也大于根节点,对应情况1(右子树大于根节点天经地义二叉树(四)--恢复二叉搜索树

  • 如果左子树最大节点小于根节点,右子树最小节点小于根节点,对应情况2

  • 情况4、5分别对根节点的左右子节点进行如上递归即可


代码:

 1public void recoverTree(TreeNode root) {
2    if (root == null) {
3        return;
4    }
5    //寻找左子树中最大的节点
6    TreeNode maxLeft = getMaxOfBST(root.left);
7    //寻找右子树中最小的节点
8    TreeNode minRight = getMinOfBST(root.right);
9
10    if (minRight != null && maxLeft != null) {
11        //左边的大于根节点,右边的小于根节点,对应情况 3,左右子树中的两个数字交换
12        if ( maxLeft.val > root.val && minRight.val < root.val) {
13            int temp = minRight.val;
14            minRight.val = maxLeft.val;
15            maxLeft.val = temp;
16        }
17    }
18
19    if (maxLeft != null) {
20        //左边最大的大于根节点,对应情况 1,根节点和左子树的某个数做了交换
21        if (maxLeft.val > root.val) {
22            int temp = maxLeft.val;
23            maxLeft.val = root.val;
24            root.val = temp;
25        }
26    }
27
28    if (minRight != null) {
29        //右边最小的小于根节点,对应情况 2,根节点和右子树的某个数做了交换
30        if (minRight.val < root.val) {
31            int temp = minRight.val;
32            minRight.val = root.val;
33            root.val = temp;
34        }
35    }
36    //对应情况 4,左子树中的两个数进行了交换
37    recoverTree(root.left);
38    //对应情况 5,右子树中的两个数进行了交换
39    recoverTree(root.right);
40
41}
42//寻找树中最小的节点
43private TreeNode getMinOfBST(TreeNode root) {
44    if (root == null) {
45        return null;
46    }
47    TreeNode minLeft = getMinOfBST(root.left);
48    TreeNode minRight = getMinOfBST(root.right);
49    TreeNode min = root;
50    if (minLeft != null && min.val > minLeft.val) {
51        min = minLeft;
52    }
53    if (minRight != null && min.val > minRight.val) {
54        min = minRight;
55    }
56    return min;
57}
58
59//寻找树中最大的节点
60private TreeNode getMaxOfBST(TreeNode root) {
61    if (root == null) {
62        return null;
63    }
64    TreeNode maxLeft = getMaxOfBST(root.left);
65    TreeNode maxRight = getMaxOfBST(root.right);
66    TreeNode max = root;
67    if (maxLeft != null && max.val < maxLeft.val) {
68        max = maxLeft;
69    }
70    if (maxRight != null && max.val < maxRight.val) {
71        max = maxRight;
72    }
73    return max;
74}


方法二:中序遍历法

思路:根据二叉搜索树的特性,根节点大于左子树最大值,小于右子树最小值,所以正常的二叉搜索树的中序遍历一定是从小到大有序的,假设二叉搜索树其中的某两个节点发生了交换,那么其中序遍历结果一定不能全局有序,所以咱们只要找出中序遍历结果中乱序的那两个节点进行交换即可

举个例子:假设交换后的二叉搜索树如下:

二叉树(四)--恢复二叉搜索树


那么其中序遍历结果则为【1、2、3、7、5、6、4】,如下

二叉树(四)--恢复二叉搜索树

交换其中乱序的7和4即可,代码如下


代码:

 1public static void recoverTree(TreeNode root) {
2    if (root == null) {
3        return;
4    }
5    List<TreeNode> treeNodeList = new ArrayList<>();
6    //中序遍历,将结果存储到List数组中
7    midOrderTraverse(root, treeNodeList);
8    if (treeNodeList.size() == 1) {
9        return;
10    }
11    TreeNode pre = null;
12    TreeNode last = null;
13    for (int i = 0; i < treeNodeList.size() - 1; ++i) {
14        //找到乱序节点 当前值比下一个值还大表明是乱序节点
15        if (treeNodeList.get(i).val > treeNodeList.get(i + 1).val) {
16            last = treeNodeList.get(i + 1);
17            if (pre == null) {
18                pre = treeNodeList.get(i);
19            }
20        }
21    }
22    //pre和last进行交换节点值,恢复二叉搜索树
23    if (pre != null && last != null) {
24        int tmp = pre.val;
25        pre.val = last.val;
26        last.val = tmp;
27    }
28}
29//中序遍历,将结果存储到List数组中
30private static void midOrderTraverse(TreeNode root, List<TreeNode> treeNodeList) {
31    if (root == null) {
32        return;
33    }
34    midOrderTraverse(root.left, treeNodeList);
35    treeNodeList.add(root);
36    midOrderTraverse(root.right, treeNodeList);
37}


以上仅是个人思路解法,觉得还不错欢迎点赞关注分享


往期精彩推荐



扫描下方二维码,关注公众号,更多精彩等你发现


以上是关于二叉树--恢复二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章

二叉树--恢复二叉搜索树

Leetcode99. 恢复二叉搜索树

数据结构~基础2~树《二叉树二叉搜索树AVL树B树红黑树》的设计~高度平衡二叉树AVL树

树99. 恢复二叉搜索树

代码随想录Day20-Leetcode654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树

二叉树进阶题------二叉树的构建及遍历;二叉搜索树转换成排序双向链表;二叉树创建字符串