介绍
要判断一千万个整数中是否存在某个数,如何查找?简单的想法是创建一个一千万大小的数组,然后遍历查找,这样即耗费空间又耗费时间。所以我们可以创建位图数组。
实际上这个数组就是个普通数组byte, int, long
类型都可以,只不过我们每次操作的是数组中一个元素的其中一位。如果要加入一个数字11,那么我们就设置这个位图数组的第11位为1
,就代表这个数存在。
比如用byte
类型实现一个位图数组。由于byte
类型是八位,所以我们就可以数组大小为实际需求的容量/8
。如果是int
类型就除以32。
所以bytes[0] 就代表了位图的[0, 7]位, byte[1] 就代表了位图的[8, 15]位, 依次...
不过由于是从零开始,所以如果要对负数进行操作时,需要加上一个offset
使所有数据变成非负,方便操作。
static class MyBitMap {
private byte[] bitmap;
private final int bit = 8;
public MyBitMap(int size) {
if (size <= 0) return;
int initSize = size / bit + 1;
bitmap = new byte[initSize];
}
public void set(int number) {
//除以8,代表这个数字在数组中的下标
//因为我们要找这个数字在整个位图中位于哪一位,而一个数组元素是8位
//所以除以8就能找到(它对应的位所在的byte类型数据)在数组中的位置。
int index = number / bit;
//number % 8 获取到在这个byte类型中,它处于哪一位
int position = number % bit;
//进行或运算,即把number对应的位修改为1。
bitmap[index] |= 1 << (bit - 1 - position);
}
public boolean contains(int number) {
//在查找这个数和set方法一样,先获得对应数组中的位置
int index = number / bit;
//再获取这个元素中对应位的位置
int position = number % bit;
//查看对应位是不是1
return (bitmap[index] & (1 << (bit - 1 - position))) != 0;
}
}
例题实现:【LC存在重复元素】链接
class Solution {
static class MyBitMap {
private int[] bitmap;
private final int bit = 32;
public MyBitMap(int size) {
if (size <= 0) return;
int initSize = size / bit + 1;
bitmap = new int[initSize];
}
public void set(int number) {
int index = number / bit;
int position = number % bit;
bitmap[index] |= 1 << (bit - 1 - position);
}
public boolean contains(int number) {
int index = number / bit;
int position = number % bit;
return (bitmap[index] & (1 << (bit - 1 - position))) != 0;
}
}
public boolean containsDuplicate(int[] nums) {
MyBitMap map = new MyBitMap((int) 1e7);
int min = Integer.MAX_VALUE;
for (int num : nums) {
min = Math.min(min, num);
}
for (int i = 0; i < nums.length; i++) {
if (map.contains(nums[i] - min)) return true;
map.set(nums[i] - min);
}
return false;
}
}