• JZ86 在二叉树中找到两个节点的最近公共祖先


    描述

    给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。

    数据范围:树上节点数满足 1 \le n \le 10^5 \1≤n≤105  , 节点值val满足区间 [0,n)

    要求:时间复杂度 O(n)O(n)

    注:本题保证二叉树中每个节点的val值均不相同。

    如当输入{3,5,1,6,2,0,8,#,#,7,4},5,1时,二叉树{3,5,1,6,2,0,8,#,#,7,4}如下图所示:

    转存失败重新上传取消

    所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。

    节点本身可以视为自己的祖先

    示例1

    输入:

    {3,5,1,6,2,0,8,#,#,7,4},5,1

    复制返回值:

    3

    复制

    示例2

    输入:

    {3,5,1,6,2,0,8,#,#,7,4},2,7

    复制返回值:

    2
    

    使用dfs加hashmap

    思路:

    1. dfs首先遍历所有的路径(这是一点看法,dfs不仅仅是遍历节点也是遍历路径)

    2. 记录两个需要的节点的路径,但是(一开始的想法是记录两个链表,这样的话会导致找到第一个公共祖先的时候,消耗时间),所以一个使用hashmap,一个使用链表,就很好,把搜索公共节点的时间压缩到o(1)。

    1. import java.util.*;
    2. /*
    3. * public class TreeNode {
    4. * int val = 0;
    5. * TreeNode left = null;
    6. * TreeNode right = null;
    7. * }
    8. */
    9. public class Solution {
    10. /**
    11. *
    12. * @param root TreeNode类
    13. * @param o1 int整型
    14. * @param o2 int整型
    15. * @return int整型
    16. */
    17. public void dfs (TreeNode root, int o1, int o2) {
    18. // write code here
    19. if(root==null)return ;
    20. list.addLast(root.val);
    21. if(root.val==o1){
    22. for(Integer x:list){
    23. hashmap1.put(x,1);
    24. }
    25. }
    26. if(root.val==o2){
    27. res=(LinkedList<Integer>)list.clone();
    28. }
    29. dfs(root.left,o1,o2);
    30. dfs(root.right,o1,o2);
    31. list.removeLast();
    32. }
    33. HashMap<Integer,Integer> hashmap1=new HashMap<Integer,Integer>();//必须用Integer
    34. // HashMap<Integer,Integer> hashmap2=new HashMap<Integer,Integer>();
    35. LinkedList<Integer> list=new LinkedList<>();
    36. LinkedList<Integer> res=new LinkedList<>();
    37. public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
    38. // write code here
    39. dfs(root,o1,o2);
    40. int ans=0x7fffffff;
    41. for(int x:res){
    42. System.out.println(x);
    43. if(hashmap1.containsKey(x)){
    44. ans=x;
    45. }
    46. }
    47. return ans;
    48. }
    49. }

    这种没有父节点 ,需要父节点的题目,可以使用hashmap存储父节点

    1. import java.util.*;
    2. /*
    3. * public class TreeNode {
    4. * int val = 0;
    5. * TreeNode left = null;
    6. * TreeNode right = null;
    7. * }
    8. */
    9. public class Solution {
    10. /**
    11. *
    12. * @param root TreeNode类
    13. * @param o1 int整型
    14. * @param o2 int整型
    15. * @return int整型
    16. */
    17. int inf=0x7fffffff;
    18. HashMap<Integer,Integer> hashmap=new HashMap<Integer,Integer>();
    19. public void dfs(TreeNode root,int parent){
    20. hashmap.put(root.val,parent);
    21. if(root.left!=null)
    22. dfs(root.left,root.val);
    23. if(root.right!=null)
    24. dfs(root.right,root.val);
    25. }
    26. HashSet<Integer> hashset=new HashSet<Integer>();
    27. public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
    28. // write code here
    29. dfs(root,inf);
    30. // System.out.println("1");
    31. hashset.add((o1));
    32. while(hashmap.get(o1)!=inf){
    33. hashset.add(hashmap.get(o1));
    34. o1=hashmap.get(o1);
    35. }
    36. // System.out.println("2");
    37. while(!hashset.contains(o2)){
    38. o2=hashmap.get(o2);
    39. }
    40. // System.out.println("3");
    41. return o2;
    42. }
    43. }

    思路:

    1. 使用hashmap保存所有的父亲节点

    2. 找到根节点开始的路径,把两台路径之中的共同父母找到(一个使用hashset一个遍历)

    1. public int lowestCommonAncestor(TreeNode root, int o1, int o2) {
    2. return helper(root, o1, o2).val;
    3. }
    4. public TreeNode helper(TreeNode root, int o1, int o2) {
    5. if (root == null || root.val == o1 || root.val == o2)
    6. return root;
    7. TreeNode left = helper(root.left, o1, o2);
    8. TreeNode right = helper(root.right, o1, o2);
    9. //如果left为空,说明这两个节点在root结点的右子树上,我们只需要返回右子树查找的结果即可
    10. if (left == null)
    11. return right;
    12. //同上
    13. if (right == null)
    14. return left;
    15. //如果leftright都不为空,说明这两个节点一个在root的左子树上一个在root的右子树上,
    16. //我们只需要返回cur结点即可。
    17. return root;
    18. }

    思路:使用递归函数

    1. 设计的时候有两点一个是递归条件,一个是终结时候的返回值

    2. 假设这个函数是取得该子树下的

            a。如果o1,o2都存在,得到公共祖先

            b。只存在一个,得到一个

            c。都不存在,返回null

    3. 递归条件是使用这个函数,实现这个函数的功能。(这一点其实就是设计这个函数功能的依据)

              a 首先看根节点是否是o1,o2,如果是则返回

              b  根节点不是的情况下

                    1 递归左节点和右节点的结果不为空,说明左节点一个,右节点一个,返回root

                    2递归左节点和右节点的结果一个为空,都在左子树,或者都在右子树,返回不为空的那个。

                    3递归左节点和右节点的结果都为空,返回空

       如果这样的话,那么看他是否能够实现刚刚说的三个功能。结果是可以实现。

    !!!我认为在设计该函数的时候,先去实现假设两个都在子树里面的情况,然后再去补充实现只有一个或者一个都没有的情况。

    4. 最后考虑临界条件,最终我们会递归到叶子节点或者是null节点,电子管这个时候,我们看null返回null,叶子节点如果是目标节点,直接返回,这个是满足刚刚的假设条件的。

  • 相关阅读:
    MDK-Keil AC6 Compiler屏蔽特定警告
    WPF性能优化:形状(Shape)、几何图形(Geometry)和图画(Drawing)的使用
    九九重阳,永恒之约 | AIGC数字永生时代,揭示永生探索的全新维度!
    2022河南萌新联赛第(七)场:南阳理工学院 F-数对
    Ubuntu基础操作
    自动打包机如何精准捆扎
    利用不同类型数据构建系统发育树
    java 版本企业招标投标管理系统源码+功能描述+tbms+及时准确+全程电子化
    3.Linux文件管理命令-----ls显示文件名
    你需要知道的关于脉动调查的一切
  • 原文地址:https://blog.csdn.net/chenziang1/article/details/126073632