首页 > 其他分享 >二叉树中查找后继节点问题

二叉树中查找后继节点问题

时间:2022-11-06 18:44:24浏览次数:76  
标签:遍历 TreeNode cur 后继 查找 二叉树 null root 节点

二叉树中查找后继节点问题

作者:Grey

原文地址:

博客园:二叉树中查找后继节点问题

CSDN:二叉树中查找后继节点问题

题目描述

给定一个二叉查找树,以及一个节点,求该节点在中序遍历的后继,如果没有则返回 null

题目链接见:LintCode 448 · Inorder Successor in BST

思路一,利用中序遍历递归解法,使用 List 收集中序遍历的节点,然后遍历一遍 List,找到给定节点的下一个节点即可,中序遍历的递归方法代码很简单,参考二叉树的先,中,后序遍历(递归,非递归)

完整代码如下

public class Solution {

    public static TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        List<TreeNode> ans = new ArrayList<>();
        if (root == null) {
            return null;
        }
        in2(root, ans);
        boolean find = false;
        for (TreeNode c : ans) {
            if (c == p) {
                find = true;
            } else if (find) {
                return c;
            }
        }
        return null;
    }

    private static void in2(TreeNode root, List<TreeNode> ans) {
        if (root == null) {
            return;
        }
        in2(root.left, ans);
        ans.add(root);
        in2(root.right, ans);
    }
}

时间复杂度 O(N),空间复杂度 O(N)

同样,中序遍历可以使用迭代方法来写,思路和递归方法一样,标记遍历到的节点 p,然后设置已遍历的标志位,如果标志位设置过,则下一个遍历到的元素就是后继节点。

完整代码如下,核心就是把中序遍历的递归解改成迭代

public class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if (root == null) {
            return null;
        }
        boolean flag = false;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (!stack.isEmpty() || cur != null) {
            if (cur != null) {
                stack.push(cur);
                cur = cur.left;
            } else {
                cur = stack.pop();
                if (cur == p) {
                    // 遍历到当前位置,记录一下
                    flag = true;
                } else if (flag) {
                    // 下一次遍历的位置,就是后继节点
                    return cur;
                }
                cur = cur.right;
            }
        }
        return null;
    }
}

思路二,使用 Morris 遍历实现中序遍历,这样可以让空间复杂度达到 O(1),时间复杂度依旧 O(N)。Morris 遍历的内容参考:Morris 遍历实现二叉树的遍历。完整代码如下

public class Solution {
    public TreeNode inorderSuccessor(TreeNode head, TreeNode p) {
        if (head == null) {
            return null;
        }
        TreeNode ans = null;
        TreeNode cur = head;
        TreeNode mostRight;
        boolean find = false;
        while (cur != null) {
            mostRight = cur.left;
            if (mostRight != null) {
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right == null) {
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                } else {
                    mostRight.right = null;
                }
            }
            if (find) {
                ans = cur;
                find = false;
            }
            if (cur == p) {
                find = true;
            }
            cur = cur.right;
        }
        return ans;
    }
}

思路三,

利用二叉搜索树的特性,如果目标节点的右孩子不为空,则目标节点右树最左节点就是目标节点的后继节点,示例如下

image

如果目标节点右孩子为空,则只需要找第一个大于目标节点值的节点即可,根据二叉搜索树的性质,每个节点的右孩子都比当前节点值大,每个节点的左孩子都比当前节点值小。

在遍历过程中,

如果当前节点的值大于目标节点的值,则先记录下当前节点(有可能是备选答案,但是不确定有没有更接近目标值的选择),然后遍历的节点往左边移动,

如果当前节点的值小于目标节点的值,一定不是后继,遍历的节点往右边移动。

如果当前节点的值等于目标节点的值,说明一定找到了后继(因为这个过程中可以确定当前节点没有右孩子,所以,到这一步,肯定是通过后继过来的,或者后继为 null),直接 break 即可。

空间复杂度O(1),时间复杂度O(h),其中 h 为二叉树的高度。

完整代码如下

public class Solution {
        public static TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if (p == null) {
            return null;
        }
        if (p.right != null) {
            return rightLeftMost(p.right);
        }
        TreeNode successor = null;
        while (root != null) {
            if (root.val > p.val) {
                successor = root;
                root = root.left;
            } else if (root.val < p.val) {
                root = root.right;
            } else {
                break;
            }
        }
        return successor;
    }

    private static TreeNode rightLeftMost(TreeNode p) {
        while (p.left != null) {
            p = p.left;
        }
        return p;
    }
}

更多

算法和数据结构笔记

标签:遍历,TreeNode,cur,后继,查找,二叉树,null,root,节点
From: https://www.cnblogs.com/greyzeng/p/16863345.html

相关文章

  • 二叉查找树
    1#include<bits/stdc++.h>2usingnamespacestd;3typedefstructSortTree4{5intdata;6structSortTree*left;7structSortTre......
  • shell-文件查找命令笔记三
    文件查找-find命令格式:find[路径][选项][操作]选项-name根据文件名查找-iname根据文件名查找,忽略大小写-perm根据文件权限查找find/etc-perm777-prun......
  • 236. 二叉树的最近公共祖先
    给定一个二叉树,找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树T的两个节点p、q,最近公共祖先表示为一个节点x,满足x是p、q......
  • 114. 二叉树展开为链表
    给你二叉树的根结点 root ,请你将它展开为一个单链表:展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。展......
  • 二叉树的最大宽度系列问题
    二叉树的最大宽度系列问题作者:Grey原文地址:博客园:二叉树的最大宽度系列问题CSDN:二叉树的最大宽度系列问题求树的最大宽度题目描述给你一棵二叉树的根节点root,返......
  • 105. 从前序与中序遍历序列构造二叉树
    给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例1:  输入:pre......
  • 二叉树的遍历总结
    二叉树的遍历总结前序:https://leetcode.cn/problems/binary-tree-preorder-traversal/中序:https://leetcode.cn/problems/binary-tree-inorder-traversal/后序:https://l......
  • 用C语言查找数字个数
    【题目名称】数9的个数【题目内容】编写程序数一下1到100的所有整数中出现多少个数字9#include<stdio.h>int main(){inti=0;   intcount=0;   for(i=1;i......
  • 力扣704 二分查找
    二分查找二分查找概述:BinarySearch,也叫折半查找。折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。 二分查找原理:首先,假设表中元素......
  • 数据结构与算法之查找
    查找【知识框架】1.查找概论查找的基本概念:查找(Searching):就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。查找表(SearchTable......