给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】
1. 遍历,时间复杂度O(N)
2. 排序(O(NlogN)),利用二分查找: logN
3. 位图解决
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:
一、位图
1.1位图的概念
所谓位图,就是用每一位来存放某种状态,适用于海量数据,整数,数据无重复的场景。通常是用来判断某个数据存不存在的。
如上例子,10个整数本应该存放需要40个字节,此时用位图只需要3个字节。
小技巧:10亿个字节大概是0.9G,可看做是1G,10亿个比特位大概是119兆,看做128兆
1.2模拟实现位图
package bitsetdemo;
import java.util.Arrays;
/**
* @Author 12629
* @Description:
*/
public class MyBitSet {
public byte[] elem;
//记录当前位图当中 存在了多少个有效的数据
public int usedSize;
public MyBitSet() {
this.elem = new byte[1];
}
/**
*
* @param n 多少位
* n = 12
* 有可能会多给一个字节,但是无所谓。
*/
public MyBitSet(int n) {
this.elem = new byte[n/8+1];
}
/**
* 设置某一位为 1
* @param val
*/
public void set(int val) {
if(val < 0) {
throw new IndexOutOfBoundsException();
}
int arrayIndex = val / 8 ;
//扩容
if(arrayIndex > elem.length-1) {
elem = Arrays.copyOf(elem,arrayIndex+1);
}
int bitIndex = val % 8;
elem[arrayIndex] |= (1 << bitIndex); //不能进行异或
usedSize++;
}
/**
* 判断当前位 是不是1
* @param val
*/
public boolean get(int val) {
if(val < 0) {
throw new IndexOutOfBoundsException();
}
int arrayIndex = val / 8 ;
int bitIndex = val % 8;
if((elem[arrayIndex] & (1 << bitIndex)) != 0) {
return true;
}
return false;
}
/**
* 将对应位置 置为 0
* @param val
*/
public void reSet(int val) {
if(val < 0) {
throw new IndexOutOfBoundsException();
}
int arrayIndex = val / 8 ;
int bitIndex = val % 8;
elem[arrayIndex] &= ~(1 << bitIndex);
usedSize--;
}
//当前位图中记录的元素的个数
public int getUsedSize() {
return usedSize;
}
}
1.3位图测试+位图排序法
package bitsetdemo;
import java.util.BitSet;
public class Test {
public static void main3(String[] args) {
int[] array = {1,3,2,13,10,3,14,18,3};
MyBitSet myBitSet = new MyBitSet(18);
for (int i = 0; i < array.length; i++) {
myBitSet.set(array[i]);
}
//位图排序法
for (int i = 0; i < myBitSet.elem.length; i++) {
for (int j = 0; j < 8; j++) {
if((myBitSet.elem[i] & (1 << j) ) != 0 ) {
System.out.println(i*8+j);
}
}
}
}
public static void main2(String[] args) {
int[] array = {1,2,3,10,4,18,130};
MyBitSet myBitSet = new MyBitSet(18);
for (int i = 0; i < array.length; i++) {
myBitSet.set(array[i]);
}
System.out.println(myBitSet.getUsedSize());
System.out.println(myBitSet.get(10));
myBitSet.reSet(10);
System.out.println(myBitSet.get(10));
}
public static void main1(String[] args) {
int[] array = {1,2,3,10,4,18,13};
BitSet bitSet = new BitSet(18);
for (int i = 0; i < array.length; i++) {
bitSet.set(array[i]);
}
System.out.println(bitSet.get(100));
}
}