这是第一篇“技术性”博客,希望以后越写越多越好咯,本科生的期许hhh
以下是题目信息
这道题运用的主要性质就是对于满二叉树任意结点编号i ,其parent(若有) 为 i/2
关键在于对算法的优化
Version 1.0
一开始只想把代码写出来,于是用了 < math.h >的pow函数,意图先算出两个结点的level,然后根据level 的差值将高位的结点“拉到”与地位的结点同一高度,然后再共同向上寻找祖先.
Version 2.0
V1的最大缺点(相对于v2)就是pow函数的使用使得代码复杂度变成了
O(1+2+…+level_a) + O(1+2+…+level_b) (毕竟pow执行了这么多次)
而显然可以通过记录一个数来使复杂度变为 O(1+2+…+level_bigger)
但仍然很慢,因为这种方法有这么几步
- 找到两个数的level
- 将较高的level降低到同一level(通过不断除以2)
- 不断同时除以2以找到共同结点(这是两个数会相同)
Version 3.0
然而V1,V2的方法还是蠢哭了。
通过观察:可以用辗转相除的方法(哪一个大就哪个除以2)来进行计算
即
while(a != b){
if(a > b)
a/=2;
else b/= 2;
}
这样循环结束两个数都成为了共同祖先,而且时间复杂度大大降低
Version 4.0
然而故事还没结束
- a /= 2; 可以通过位运算 改变为 a >>= 1;
cin、cout 可以通过改为scanf 和 printf 提升效率
于是最终代码如下
#include <iostream>
using namespace std;
int main(){
int T;cin >> T;
for(int testcase = 0; testcase < T; ++testcase){
int a,b; scanf("%d %d",&a,&b);
while(a != b){
if(a > b) a >>= 1;
else b >>= 1;
}
printf("%d\n",a);
}
}
当然遗留了一些问题,这里做个小笔记
- cin、cout 的具体实现
- 乘除法的具体实现(我知道我上了数电…看来我还得去复习一下?)
- 对上一条的延伸:浮点数乘除法的实现