有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为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;
}
好吧。。。人就是这样一步一步进步的(摊手/)