Python程序员面试算法宝典---解题总结: 第9章 大数据 9.7 如何统计不同电话号码的个数


# -*- coding: utf-8 -*-

'''
Python程序员面试算法宝典---解题总结: 第9章 大数据 9.7 如何统计不同电话号码的个数

题目:
已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

分析:
记得似乎是编程珠玑中的题目。
最简单的方法,设置哈希(对应于python中的字典),建立:
<号码字符串, 该号码字符串出现的次数>。
又或者可以利用Trie树,即前缀树,实际就是一个多叉树,
每个节点设置10个孩子节点分别表示数字0~9,
最后一个数字节点后面的节点用于统计该号码的个数。

关键:
1 书上解法
求解数据重复的问题优先用位图方法。
8位电话号码范围在:
0000 0000 ~ 9999 9999
可以用每个bit表示一个电话号码,则需要1亿个bit,大约等于100MB。
例如
0000 0000 对应位图最后1位为         0x0000...000001
0000 0001 对应位图倒数第二位为      0x0000...000010
0000 0012 对应位图倒数第13位为      0x0000...0001 0000 0000 0000
总结:
也就是数字n对应位图倒数第n位为1。
位图的实现是整数数组
考虑到一个整数占据4字节,确定一个电话号码对应在位图中的下标用
P / 32 (因为每个整数是4字节,即32比特),计算在该位图下标对应元素中的位置则为 P % 32

2 注意
题目要求的是不同电话号码的个数,而不是每个电话号码出现的次数,
因此不能用哈希做,位图适合于求解:
存在重复的问题+数据量大的问题

3 没有想到
是因为忘记了位图的原理:
通过某1位bit是否为1来表示对应数字是否出现过。
位图适用:
大数据查找,数据判重
位图的实现是整数数组,因为一个整数是4字节即32bit,
所以确定位图中该phone的的下标为: bitmap[phone / 32]
确定该下表值中的bit位位: 1 << (phone % 32)

参考:
Python程序员面试算法宝典
'''


def phoneToBit(bitmap, phone):
    bitIndex = 1 << (phone % (4 * 8))
    index = phone / (4 * 8)
    # 注意这里是 或|=而不是 不等于
    bitmap[index] |= bitIndex


def statsPhones(phones):
    if not phones:
        return
    # 创建bitmap, 1 0000 0000 / 32
    size = 100000000 / 32 + 1
    bitmap = [0 for i in range(size)]
    for phone in phones:
        if not isinstance(phone, int):
            continue
        phoneToBit(bitmap, phone)
    # 统计最终的结果
    count = 0
    for i in range(0, 100000000):
        index = i / 32
        bitIndex = i % 32
        value = (bitmap[index] & (1 << bitIndex))
        if value != 0:
            count += 1
    return count


def process():
    phones = [82652497, 82432462, 82434021, 82482071,
              82652497, 82432462, 82434021, 82482071,
              81111111]
    # phones = [0, 1, 2, 10,
    #           0, 1, 2, 10,
    #           11111111]
    result = statsPhones(phones)
    print result


if __name__ == "__main__":
    process()

 

你可能感兴趣的:(Python程序员面试算法宝典)