大数据
题目一
普通解法:利用位图,将32位的整数分别对应到个数为2^32次位图数组中,其大小为500M,则可以找到40亿个中不存在的数。
进阶解法:例如只给3KB,则找到512为离3000/4最近的2的幂指数,将32位数均匀分成512份,每份有836088个数,再将40亿个数每个/836088,发现哪份少了就利用3KB空间对该份进行细分,直至分出每份为1的份数。
进阶解法2:只能申请有限个变量。二分,统计词频,找到不满的继续分。
题目二
经典方法:可以利用哈希函数或者布隆过滤器。
补充问题:利用二维堆来解决
- 将海量词汇利用哈希函数进行离散化分类,再根据要求取模,分层k堆,每个堆为大根堆进行排序。
- 设置一个总堆为大根堆。首先将每个堆的第一个元素放入总堆中,弹出一个最大的,再将这个最大的所在堆中第二大的放入,再进行弹出操作。直至找到top100。
题目三
- 常规解法:可以利用两个bit来表示该数出现过的次数,其中10代表出现过两次。预计使用小于1G的空间。
- 补充解法:例如用10KB空间,其最多可以放2048个无符号整型数组数据,将2^32个数字范围分成2048份,再对40亿个数进行计数,若全部计数完毕后第k个区间包含了第20亿个数,则再在该区间进行细分。
腾讯题
10G文件存放无序整型数据,如何利用6G内存,将其变为有序文件。
- 例如分成25个小根堆,每个小根堆含有227个数,按照其分类
- 优化方案:例如有10条数据,有容量为3的大跟堆。遍历所有数据,若大根堆中数据个数小于3则放入,若小于大根堆顶端数据,则放入,否则忽略。一遍遍历完后,将最小的3个数输出,接着重新遍历,但不放进已经放入过的数据。
题目四
public static int flip(int n) {
return n ^ 1; // 进行翻转
}
public static int sign(int n) {
return flip((n >> 31) & 1); // 找到符号位
}
public static int getMax1(int a, int b) {
int c = a - b; // 比较a和b
int scA = sign(c); //a和b之差的正负
int scB = flip(scA); //a和b之差的正负 的相反数
return a * scA + b * scB;
}
public static int getMax2(int a, int b) {
int c = a - b;// 比较a和b
int sa = sign(a); // a的正负
int sb = sign(b); // b的正负
int sc = sign(c); // a-b的正负
int difSab = sa ^ sb; // a和b符号不一样为1;一样为0
int sameSab = flip(difSab); // a和b符号不一样为0;一样为1
int returnA = difSab * sa + sameSab * sc; // a和b符号不一样为1且a>0,a和b符号一样且a>b
int returnB = flip(returnA);
return a * returnA + b * returnB;
}
题目五
- 判断2的幂
- 在二进制下只有一位是1
- 法1:拿到这个数最右侧的1:
x & (~ x + 1)
,看与该数是否相等,相等则符合。 - 法2:
x & (x - 1) == 0
则只有一位1
- 判断4的幂
- 在二进制上只有一个1,且1必须在0、2、4、6、8···位上
- 首先去验证是2的幂
- 接着验证
x & 010101010101 != 0
则为4的幂
题目六
加法:
- 异或运算相当于无进位相加
- 进位信息可以由两数与运算并左移得到
- 再将其不断进行以上操作,直至进位信息为0,则答案为异或运算结果
int add(int a, int b) {
int sum = a;
while (b != 0) {
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
减法:
- a - b为a加上b的相反数,b的相反数为b取反再加1
乘法:
`int multi(int a, int b) {
int res = 0;
while (b != 0) {
if ((b & 1) != 0) {// b的最后一位不为0
res = add(res, a);
}
a = (a << 1);
b = ((unsigned)b >> 1);//无符号右移
}
return res;
}`
除法:
- 让除数分别左移31…0位,让被除数尝试去减,假设左移3位可以减,则商的结果中第4位一定是1,然后将被除数减后的结果当作新的被除数,重复上述操作
int myDiv(int a, int b) {
int x = isNeg(a) ? negNum(a) : a;
int y = isNeg(b) ? negNum(b) : b;
int res = 0;
for (int i = 31; i >= 0; i--) {
if ((x >> i) >= y) {
res = (res | (1 << i));
x = minuss(x, (y << i));
}
}
return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
}