先来分析:考察的数据结构是二叉树,考察的算法是二叉树的深度遍历。假设当前节点A,A到o1,o2的距离最小的条件限制有
1 A 均能到o1,o2
2 A 到 o1,o2 的路程和最小
所以思路变成先遍历外面的大树,通过遍历然后针对每一个节点进行可达性以及路程的计算,迭代更新路程最小的节点,其实对于树的遍历,相当于是我们在做 for 循环,然后针对循环到的每一个元素,再进行深入的探查,这是二叉树这类题的常用手段,那么如何进行探查尼?还是dfs.所以一般二叉树都要用两个“循环”,一次是以最顶上的根节点为开始的“循环”,一次是以大循环遍历到的点,再以这个点为根节点进行循环的子循环。

TreeNode[] res,int [] dp 用了两个对象来记录中间结果,作用域比较广,比较方便。


public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
    // write code here
    if(root==null){
        return -1;
    }
    TreeNode [] res=new TreeNode[1];
    int [] dp=new int [1];
    preOrder(root,o1,o2,res,dp);
    return res[0].val; 
}

//大循环 dfs,遍历整棵大树
public void preOrder(TreeNode root,int o1,int o2,TreeNode[] res,int [] dp){
    if(root==null){
        return ;
    }
    int step1=getSteps(root,o1,0);
    int step2=getSteps(root,o2,0);
    if(step1!=-1 && step2!=-1){//排除不可达的点,这里有剪枝优化,因为如果根都不可达,左右子树一定是不可达的,因此只下探这种情况
        int steps=step1+step2;
        if(dp[0]!=0){
            if(dp[0]>steps){//迭代更新
                dp[0]=steps;
                res[0]=root;
            }
        }else{//初始化
            dp[0]=steps;
            res[0]=root;
        }
        preOrder(root.left,o1,o2,res,dp);
        preOrder(root.right,o1,o2,res,dp);
    }
}

//以大树的每一个节点为根节点进行 dfs ,开始子循环遍历
public int getSteps(TreeNode root,int o1,int step){
    if(root!=null){
        if(root.val==o1){//找到了目标值了,返回 step 路程数
            return step;
        }else{
            return Math.max(getSteps(root.left,o1,step+1),getSteps(root.right,o1,step+1)); //继续向下循环,但一定是左右子树最大的路径。主要是和 -1 比较
        }
    }else{
        return -1; //遍历到了空节点,说明不可达,路程为-1
    }
}