最近公共祖先

来源:互联网 发布:怪物猎人3g数据库下载 编辑:程序博客网 时间:2024/06/06 04:15

链接:https://www.nowcoder.com/questionTerminal/70e00e490b454006976c1fdf47f155d9?orderByHotValue=1&mutiTagIds=593&page=1&onlyReference=false
来源:牛客网

有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为1。现在有两个结点a,b。请设计一个算法,求出a和b点的最近公共祖先的编号。
给定两个int a,b。为给定结点的编号。请返回a和b的最近公共祖先的编号。注意这里结点本身也可认为是其祖先。
测试样例:
2,3
返回:1


思路:a跟b分别找自己的父节点,当a==b时就是公共的父节点,但要求的是最近的,那么将所得的父节点存比较最大的一点就是最近的父节点。

看到这题时第一反应递归暴力查找,结果答案对了,预料之中超时了。。。

//法一:递归 public  int getLCA(int a, int b) {        if(a==1||b==1)                return 1;            if(a==b)                return a;            int x = getLCA(a/2,b);            int y = getLCA(a,b/2);            return Math.max(x, y);      }

超时原因就是重复算了很多已经算过的值,那么解决这问题,我先想到用动态规划吧,就开始开动了

把递归转动态规划:

public  int getLCA(int a, int b) {int dp[][] = new int[a+1][b+1];    for(int i=1;i<=a;++i)        dp[i][1] = 1;    for(int i=1;i<=b;++i)        dp[1][i] = 1;    for(int i=2;i<=a;++i){        for(int j=2;j<=b;++j){            if(i==j){                dp[i][j]=i;                continue;            }            dp[i][j]=Math.max(dp[i/2][j],dp[i][j/2]);        }    }    return dp[a][b]; }

答案肯定对了,好了等我写完dp后提交,内存超限。。。。顿时无语。。。

好吧那很明显唯一的办法就是dp状态压缩了
直接用一维存每个index的最近父节点,然后再搜,初始化时间复杂度为O(n),搜索O(logn),提交后,唉总算过了。。。

public  int getLCA(int a, int b) {    int m = Math.max(a,b)+1;    int dp[] = new int[m];    int k = 1;    int index = 1;    dp[1]=1;    int t;    for(int i=2;i<m;++i)        dp[i]=i/2;    while(dp[a]!=dp[b]){        if(dp[b]>dp[a]){            b>>=1;            continue;        }        if(dp[a]>dp[b]){            a>>=1;            continue;        }    }    return dp[a]; }

后面又发现其实不用dp数组存每个index的最近父节点,直接搜时间复杂度为O(logn)

 int getLCA(int a, int b) {      // write code here      while(a != b)          {          if(a > b)              a /= 2;          else              b /= 2;      }      return a;  }

好吧。。。人就是这样一步一步进步的(摊手/)

原创粉丝点击