最近公共祖先

链接: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;
  }

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值