编程之美(五)快速找出故障机器

关心数据挖掘和搜索引擎的程序员都知道,我们需要很多的计算机来存储和处理海量数据。然而,计算机难免出现硬件故障而导致网络联系失败或死机。为了保证搜索引擎的服务质量,我们需要保证每份数据都有多个备份。

简单起见,我们假设一个机器仅存储一个标号为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 sum1sum2=x+y m u l 1 / m u l 2 = x ∗ y mul1 / mul2 = x * y mul1/mul2=xy( x 、 y x、y xy为故障机器 I D ID ID);遍历 x 、 y x、y xy,满足这两个条件即为故障机器 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;
}

结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值