題目描述:
已知某個文件內包含一些電話號碼,每個號碼為 8 位數字,統計不同號碼的個數。
分析與解答:
這個題目本質上也是求解數據重復的問題,對於這類問題,首先會考慮位圖法。對本題而言,8 位電話號碼可以表示的范圍為 00000000~99999999。如果用 1bit 表示一個號碼,那么總共需要 1 億個 bit,總共需要大約 100MB 的內存。
通過上面的分析可知,這道題的主要思路:申請一個位圖並初始化為 0,然后遍歷所有電話號碼,把遍歷到的電話號碼對應的位圖中的 bit 設置為 1。當遍歷完成后,如果 bit 值為 1,則表示這個電話號碼在文件中存在,否則這個 bit 對應的電話號碼在文件中不存在。所以 bit 值為 1 的數量就是不同電話號碼的個數。
求解這道題時,最核心的算法是如何確定電話號碼對應的是位圖中的哪一位。下面重點介紹這個轉化的方法,這里使用下面的對應方法。
00000000 對應位圖最后一位:0×0000…000001。
00000001 對應位圖倒數第二位:0×0000…0000010(1 向左移 1 位)。
00000002 對應位圖倒數第三位:0×0000…0000100(1 向左移 2 位)。
……
00000012 對應位圖的倒數第十三位:0×0000…0001 0000 0000 0000。
通常而言,位圖都是通過一個整數數組來實現的(這里假設一個整數占用 4B)。由此可以得出,通過電話號碼獲取位圖中對應位置的方法為(假設電話號碼為 P):
1)通過 P/32 就可以計算出該電話號碼在 bitmap 數組中的下標(因為每個整數占用 32bit,通過這個公式就可以確定這個電話號碼需要移動多少個 32 位,也就是可以確定它對應的 bit 在數組中的位置)。
2)通過 P%32 就可以計算出這個電話號碼在這個整型數字中具體的 bit 的位置,也就是 1 這個數字對應的左移次數。因此,只要把 1 向左移 P%32 位,然后把得到的值與這個數組中的值做或運算,就可以把這個電話號碼在位圖中對應的位設置為 1。
這個轉換的操作可以通過一個非常簡單的函數來實現: