在 O(1) 内求一个数二进制形式时最低为 1 的位
例如 12 的二进制形式 1100,则 12 二进制形式时最低为 1 的位为倒数第 3 位。
如果我们从最低位向最高位一位一位判断的话,时间复杂度为 O(n),显然是无法满足要求的。
既然常规途径不符合要求,我们就要考虑一些技巧性的东西来帮我们寻找答案。
我首先想到的是位操作。关于位操作你可以参考一下我之前的一篇博客绝对值函数(位操作法)。基本上所有的高级语言都提供了对位操作的支持,由于最近我在学习 Python,所以这次我就尝试用 Python 来解决这个问题。
# -*- coding: utf-8 -*-
# python 2.7.3
# lob.py 2014/06/20
# author: sfyumi
# email: [email protected]
import math
#least one bit
def lobof(number):
num = ~number
num += 1
num = num^number
num =~ num
num += 1
lob = int(math.log(num)/math.log(2))
return lob
number = 14
print lobof(number)
我们先来分析算法,接下来我会一句一句讲解这段代码。
我们以 14 为例来分析:
a=14; // 二进制形式为 0 1110
b=-a; // 二进制形式为 1 0010(补码)
c=a^b; // 二进制形式为 1 1100(十进制为 -7)
现在我们已经把原来的 a,14(1110) 转化成了 c,-7(1100),c 以 a 最低为 1
的位为分界线,比这一位高的位全部为 1,这一位和比它低的位全部为零(11|00),接下来我们就可以发挥想象力把 c 再转换成我们需要的形式。
在把 c 转化成我们想要的形式之前,我们还可以优化一下之前的代码。
我们知道,-14 其实就是 14 的补码,也就是对 14 取反再加 1,而直接位操作在效率上是优于在变量之前加负号来求负值的,所以可以把
b=-a;
优化成
b=~a;
b++;
则上面的代码可以改为
a=14; // 二进制形式为 0 1110
b=~a; // 二进制形式为 1 0001(取反)
b++; // 二进制形式为 1 0010(补码)
c=a^b; // 二进制形式为 1 1100(十进制为 -4)
现在我们再考虑把 c 转换成我们需要的形式
c=~c; // 二进制形式为 0 0011(取反)
c++; // 二进制形式为 0 0100(十进制为 4)
d=log(c,2) // 以 2 为底 4 的对数为 2
最终结果 d=2,则 14 二进制形式时最低为 1 的位为倒数第二位。
则代码最终的形式为
a=14; // 二进制形式为 0 1110
b=~a; // 二进制形式为 1 0001(取反)
b++; // 二进制形式为 1 0010(补码)
c=a^b; // 二进制形式为 1 1100(十进制为 -4)
c=~c; // 二进制形式为 0 0011(取反)
c++; // 二进制形式为 0 0100(十进制为 4)
d=log(c,2) // 以 2 为底 4 的对数为 2
算法的证明我会在最后给出,下面我们来分析 Python 代码
# -*- coding: utf-8 -*-
# python 2.7.3
# 上面一行是字符编码声明与编译环境
# lob.py 2014/06/20
# author: sfyumi
# email: [email protected]
# 上面三行是版权声明
import math
# 引入 Python 的 math 模块,log 函数在 math 模块里
#least one bit
def lobof(number): # 函数定义,求 number 二进制形式时最低为 1 的位
num = ~number # 取反
num += 1 # num++
num = num^number # num 等于 num 和 number 异或
num =~ num # num 本身取反
num += 1 # num++
lob = int(math.log(num)/math.log(2))
# log 函数是以 e 为底求一个数的对数即 ln,则log(num,2) 可以转化成 ln(num)/ln(2),然后强制转化成 int 型
return lob # 返回值
number = 14
print lobof(number)
等过几天闲了再写吧。偷个懒儿先。