1. 这个题目源自于位运算时候看到的问题,题目可以做个简化如: 有5个随机数,范围在0-9之间,写算法将不在随机数中的数进行求出来。

有随机数[4, 8, 7, 5, 7],则不在其中的随机数为0 1 2 3 6 9

2. 思路

  1. 常规思路就是开辟一个长度为10的数组,将随机数遍历并放入数组指定的索引位置,并改变对应索引的值为1,则值为0索引为目标不存在的数。 假设我们开辟的是int型数组,每个int占32位,一共需要的是32 * 10 = 320bit = 40byte
  2. 另外一种做法则是借助bitmap进行位运算,其思想就是0表示该位置对应的数没有,1表示存在,如4,我们用比特表示则位10000,第四位为1,说明存在4。(具体位运算的基础知识,参考​​位运算​​)对于10个数,我们只需要 10个bit位即可进行表示,非常之节省空间。

3. 借助BitSet进行运算

T

public class Test {
public static void main(String[] args) {
Random random = new Random();
List<Integer> list = new ArrayList<>();
// 创建5个随机数,每个数字再0-10范围内(左闭右开)
for (int i = 0; i < 5; i++) {
list.add(random.nextInt(10));
}
System.out.println("产生的随机数为:" + list);
// 使用bitset,无参默认是64bit,参数表示你想放置的数字范围
BitSet bitSet = new BitSet(10);
for (int i = 0; i < list.size(); i++) {
// 使用set方法,向开辟的10个bit位放元素,如将4放入,则在位图中存放形式为:
// 0000010000
bitSet.set(list.get(i));
}
// 遍历10位bit,对bit位为0的进行输出(0表示无元素,1表示有元素)
for (int i = 0; i < 10; i++) {
// 用get函数,boolean get(int index),false表示为0
if (!bitSet.get(i)) {
System.out.println(i);
}
}
}
}

4. 即然了解了位图是干什么的,那么再来举个例子,巩固一下

问题:如何在1到n的连续整数缺失两个数,如何找到缺失的两个数字?

JAVA位运算题有1千万个随机数,随机数的范围在1到1亿之间。现在要求写出一种算法,将1到1亿之间没有在随机数中的数求出来?_位图


方法1:假如我们有数组[1,2,3,4,5],其中1,5 缺失,我们可以利用x+y和x*y求出缺失。假设缺失设为x和y,则有

x + y + 2 + 3 + 4 = (1+5)*5 / 2;
x * y * 2 * 3 * 4 = 1 * 2 * 3 * 4 * 5;
相信看到这,你已经觉得开销很大了,那么请看方法2

方法2:同样利用位图,那么只占用很少的内存即可找出缺失

public class Test {
public static void main(String[] args) {
// 当然对缺失任意位数的都可以找到
// 假设缺失两个数字5, 9
printMissingNumber(new int[]{1, 2, 3, 4, 6, 7, 8, 10}, 10);
}
private static void printMissingNumber(int[] numbers, int count) {
int missingCount = count - numbers.length;
BitSet bitSet = new BitSet(count);

for (int number : numbers) {
bitSet.set(number - 1);
}

System.out.printf("Missing numbers in integer array %s, with total number %d is %n",
Arrays.toString(numbers), count);
int lastMissingIndex = 0;

for (int i = 0; i < missingCount; i++) {
lastMissingIndex = bitSet.nextClearBit(lastMissingIndex);
System.out.println(++lastMissingIndex);
}
}
}

​参考代码​

5. 思考

上述的题解只是做个例子,位图一般适用于大数据中的找出,查重等工作。如在1亿数据中查询某些不存在的数就可以使用该方法。数组的形式占用空间是位图占用空间的32倍(int型举例)。
第一次研究位运算,若有问题,恳请指出。