求一个数二进制形式时最低为 1 的位

题解

在 O(1) 内求一个数二进制形式时最低为 1 的位

例如 12 的二进制形式 1100,则 12 二进制形式时最低为 1 的位为倒数第 3 位。

如果我们从最低位向最高位一位一位判断的话,时间复杂度为 O(n),显然是无法满足要求的。

O(1) 方法

既然常规途径不符合要求,我们就要考虑一些技巧性的东西来帮我们寻找答案。
我首先想到的是位操作。关于位操作你可以参考一下我之前的一篇博客绝对值函数(位操作法)。基本上所有的高级语言都提供了对位操作的支持,由于最近我在学习 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 代码分析

算法的证明我会在最后给出,下面我们来分析 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)

证明

等过几天闲了再写吧。偷个懒儿先。

你可能感兴趣的:(二进制,python,位操作)