关心数据挖掘和搜索引擎的程序员都知道,我们需要很多的计算机来存储和处理海量数据。然而,计算机难免出现硬件故障而导致网络联系失败或死机。为了保证搜索引擎的服务质量,我们需要保证每份数据都有多个备份。
简单起见,我们假设一个机器仅存储一个标号为ID的记录(假设ID是小于10亿的整数),假设每份数据保存两个备份,这样就有两个机器存储了同样的数据。
- 1.在某个时间,如果得到一个数据文件ID的列表,是否能够快速找出这个表中仅出现一次的ID?
- 2.如果知道只有一台机器死机(也就是说只有一个备份丢失)呢?如果有两台机器死机呢(假设同一个数据的两个备份不会同时丢失)?
解法一
在一堆ID中找到一个ID,这个ID只出现一次,其它都出现2次。
思路:使用数组存储ID出现的次数,然后遍历该数组,找出只出现一次的ID;时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)
void find_1(vector<int> array) {
int n = array.size();
vector<int> ans(n, 0);
for (int i = 0; i < n; ++i) {
ans[array[i]]++;
}
for (int i = 0; i < n; ++i) {
if (ans[i] == 1)
cout << i << endl;
}
}
解法二
思路:使用哈希表存储ID出现的次数,每次遇见一个ID,就向哈希表中增加一个元素;如果这个ID出现的次数为2,那么就从哈希表中删除该元素;时间复杂度为 O ( n ) O(n) O(n),空间复杂度最好情况下为 O ( 1 ) O(1) O(1),最坏情况下为 O ( n ) O(n) O(n)
void find_2(vector<int> array) {
map<int, int> mp;
int n = array.size();
for (int i = 0; i < n; ++i) {
mp[array[i]]++;
if (mp[array[i]] == 2) {
mp.erase(array[i]);
}
}
for (auto m : mp) {
cout << m.first << " ";
}
cout << endl;
}
解法三
思路:
- (1)当列表中仅有一个 I D ID ID出现了 1 1 1次,那么我们可以考虑异或的性质, x x x ^ x = 0 x = 0 x=0, x x x ^ 0 0 0 = x x x;我们将所有的元素进行异或,得到的最终值即为只出现一次的 ID
- (2)当列表中有两个 I D ID ID出现了一次,那么我们用上面的方法显然行不通;我们可以将该问题转换为上一个问题,先将所有元素进行异或得到一个非零值 x x x,然后找到 x x x的二进制表示中第一个非 0 0 0的位,再根据该位判断列表中的元素,将元素分为两边,然后两边中的所有元素分别进行异或,最后得到两个非零值即为出现一次的两个 I D ID ID
//列表中只有一个ID出现了1次
void find_3x(vector<int> array) {
int x = array[0];
for (int i = 1; i < array.size(); ++i) {
x ^= array[i];
}
cout << x << endl;
}
//列表中有两个ID出现了1次
int FindBit(int x);
bool IsBit(int x, int indexBit);
void find_3y(vector<int> array) {
int x = array[0];
for (int i = 1; i < array.size(); ++i) {
x ^= array[i];
}
int indexBit = FindBit(x);
int num1 = 0, num2 = 0;
for (int i = 0; i < array.size(); ++i) {
if (IsBit(array[i], indexBit))
num1 ^= array[i];
else
num2 ^= array[i];
}
cout << num1 << " " << num2 << endl;
}
int FindBit(int x) {
int indexBit = 0;
while ((x & 1) == 0 && indexBit < 8 * sizeof(int)) {
x = x >> 1;
++indexBit;
}
return indexBit;
}
bool IsBit(int x, int indexBit) {
x = x >> indexBit;
return (x & 1);
}
解法四
思路:求出原 I D ID ID序列的和 s u m 1 sum1 sum1及乘积 m u l 1 mul1 mul1,当前 I D ID ID序列的和 s u m 2 sum2 sum2及乘积 m u l 2 mul2 mul2; s u m 1 − s u m 2 = x + y sum1 - sum2 = x + y sum1−sum2=x+y, m u l 1 / m u l 2 = x ∗ y mul1 / mul2 = x * y mul1/mul2=x∗y( x 、 y x、y x、y为故障机器 I D ID ID);遍历 x 、 y x、y x、y,满足这两个条件即为故障机器 I D ID ID
void find_4(vector<int> array1, vector<int> array2) {
int sum1 = 0, sum2 = 0;
int mul1 = 1, mul2 = 1;
for (int i = 0; i < array1.size(); ++i) {
sum1 += array1[i];
mul1 *= array1[i];
}
for (int i = 0; i < array2.size(); ++i) {
sum2 += array2[i];
mul2 *= array2[i];
}
int a = sum1 - sum2;
int b = mul1 / mul2;
for (int i = 0; i < a; ++i) {
for (int j = 0; j < b; ++j) {
if ( i + j == a && i * j == b) {
cout << i << " " << j << endl;
return;
}
}
}
}
测试及代码:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
void find_1(vector<int> array) {
int n = array.size();
vector<int> ans(n, 0);
for (int i = 0; i < n; ++i) {
ans[array[i]]++;
}
for (int i = 0; i < n; ++i) {
if (ans[i] == 1)
cout << i << endl;
}
}
void find_2(vector<int> array) {
map<int, int> mp;
int n = array.size();
for (int i = 0; i < n; ++i) {
mp[array[i]]++;
if (mp[array[i]] == 2) {
mp.erase(array[i]);
}
}
for (auto m : mp) {
cout << m.first << " ";
}
cout << endl;
}
//列表中只有一个ID出现了1次
void find_3x(vector<int> array) {
int x = array[0];
for (int i = 1; i < array.size(); ++i) {
x ^= array[i];
}
cout << x << endl;
}
//列表中有两个ID出现了1次
int FindBit(int x);
bool IsBit(int x, int indexBit);
void find_3y(vector<int> array) {
int x = array[0];
for (int i = 1; i < array.size(); ++i) {
x ^= array[i];
}
int indexBit = FindBit(x);
int num1 = 0, num2 = 0;
for (int i = 0; i < array.size(); ++i) {
if (IsBit(array[i], indexBit))
num1 ^= array[i];
else
num2 ^= array[i];
}
cout << num1 << " " << num2 << endl;
}
int FindBit(int x) {
int indexBit = 0;
while ((x & 1) == 0 && indexBit < 8 * sizeof(int)) {
x = x >> 1;
++indexBit;
}
return indexBit;
}
bool IsBit(int x, int indexBit) {
x = x >> indexBit;
return (x & 1);
}
void find_4(vector<int> array1, vector<int> array2) {
int sum1 = 0, sum2 = 0;
int mul1 = 1, mul2 = 1;
for (int i = 0; i < array1.size(); ++i) {
sum1 += array1[i];
mul1 *= array1[i];
}
for (int i = 0; i < array2.size(); ++i) {
sum2 += array2[i];
mul2 *= array2[i];
}
int a = sum1 - sum2;
int b = mul1 / mul2;
for (int i = 0; i < a; ++i) {
for (int j = 0; j < b; ++j) {
if ( i + j == a && i * j == b) {
cout << i << " " << j << endl;
return;
}
}
}
}
int main() {
vector<int> array = {1, 1, 2, 2, 4};
find_1(array);
find_2(array);
//test1
find_3x(array);
//test2
vector<int> array_y = {1, 1, 2, 2, 5, 4};
find_3y(array_y);
vector<int> array1 = {1, 1, 2, 2, 5, 5};
vector<int> array2 = {1, 1, 2, 5};
find_4(array1, array2);
return 0;
}
结果: