由一道算法题引发的思考,使用bitmap进行数据处理
题目
判断数组输入的五个数(取值1~13)是否是连续的,可以输入0,最多有4个,其中0可以代表任意数字,比如13450 可以 是12345
思路:其实里面的规律是,数组5个数里面除了0外max-min<5,除了0以外其他数不能重复,所以主要判断除了0以外重复问题
- 使用HashSet
- 使用数组进行hash
- 这也是最为巧妙的一种,使用更加节约内存的bitmap位映射
什么是bitMap?
举个栗子 有 2 4 1 6 7 3 这几个数要排序,我们可以用一个byte的空间来存储他们。初始为 00000000,遍历数组将每一个数按照的大小对应下标把0位置为1,比如第一个数2,就改byte为 0010 0000,以此类推,最后结果为 0111 1011 遍历这个byte就得出排序后结果,bitmap的好处在于按位存储,节省内存,和外归并排序和hash+topN小顶堆一样,也常用于海量数据处理。
回到这个题目,本身可以使用一个大于14位的变量来存储,比如int(32位,足够储存0~13),然后遍历五个元素,判断元素值作为索引对应位是否为1,如果这个数不是0,对应位又为1,那就是碰撞了(重复了),return false,如果不是,则将该对应位置1。循环结束后判断max-min。
至于如何将对应位读取或修改,可以使用位操作,比如将0的第4位置1,只要将1000…0000(一个int长度 )无符号右移4位,再相与 & 即可。判断是否为1,则相或 | 即可。而我们知道,1000…0000(int)刚好是Integer.MIN_VALUE的补码(计算机都是补码存储)。
public class Solution {
public boolean isContinuous(int [] numbers) {
if(numbers.length<1) return false;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
//bitMap
int map = 0;
//补码10^31
int temp = Integer.MIN_VALUE;
for(int i=0;i<numbers.length;i++) {
temp >>>= numbers[i];
int check = map&temp;
if(check!=0 && numbers[i]!=0) return false;
else {
map |=temp;
temp<<=numbers[i];
}
if(numbers[i]>max) max = numbers[i];
if(numbers[i]<min&&numbers[i]!=0) min = numbers[i];
}
if(max-min<5) return true;
else return false;
}
}