在3n + 1个数字中找到唯一的数字

时间:2015-07-05 19:48:54

标签: algorithm

我在接受采访时被问到这个问题。

  

鉴于此,有3n + 1个数字。这些数字中的n个出现在三元组中,只有1个出现在单个时间内。我们如何在线性时间内找到唯一的数字,即O(n)?这些数字没有排序。

请注意,如果有2n + 1个数字,其中n个成对出现,我们可以对所有数字进行异或,以找到唯一的数字。面试官告诉我,可以通过点操作来完成。

3 个答案:

答案 0 :(得分:8)

你可以发明一个3nary XOR(称之为XOR3)操作,它在base 3而不是base 2中运行,并且简单地将每个3nary数字模3(当通常XOR采用2nary digit modulo 2时)

然后,如果您XOR3所有数字(首先将它们转换为3nary),您将获得唯一的数字(在基数3中,因此您需要将其转换回来)。

但复杂性并不完全是线性的,因为从/到基数3的转换需要额外的对数时间。但是,如果数字范围是常数,则转换时间也是恒定的。

C ++代码(故意详细):

vector<int> to_base3(int num) {
  vector<int> base3;
  for (; num > 0; num /= 3) {
    base3.push_back(num % 3);
  }
  return base3;
}

int from_base3(const vector<int> &base3) {
  int num = 0;
  for (int i = 0, three = 1; i < base3.size(); ++i, three *= 3) {
    num += base3[i] * three;
  }
  return num;
}

int find_unique(const vector<int> &a) {
  vector<int> unique_base3(20, 0); // up to 3^20
  for (int num : a) {
    vector<int> num_base3 = to_base3(num);
    for (int i = 0; i < num_base3.size(); ++i) {
      unique_base3[i] = (unique_base3[i] + num_base3[i]) % 3;
    }
  }

  int unique_num = from_base3(unique_base3);
  return unique_num;
}

int main() {
  vector<int> rands { 1287318, 172381, 5144, 566546, 7123 };
  vector<int> a;
  for (int r : rands) {
    for (int i = 0; i < 3; ++i) {
      a.push_back(r);
    }
  }
  a.push_back(13371337); // unique number

  random_shuffle(a.begin(), a.end());

  int unique_num = find_unique(a);
  cout << unique_num << endl;
}

答案 1 :(得分:8)

  1. 计算3n + 1个数字组中每个位出现的次数。
  2. 减少每个位数模3。
  3. 剩下的是单个数字的位模式。
  4. 哦,dreamzor(上图)打败了我。

答案 2 :(得分:3)

byte [] oneCount = new byte [32];

int [] test = {1,2,3,1,5,2,9,9,3,1,2,3,9};

for (int n: test) {
    for (int bit = 0; bit < 32; bit++) {
        if (((n >> bit) & 1) == 1) {
            oneCount[bit]++;
            oneCount[bit] = (byte)(oneCount[bit] % 3);
        }
    }
}

int result = 0;
int x = 1;

for (int bit = 0; bit < 32; bit++) {
    result += oneCount[bit] * x;
    x = x << 1;
}

System.out.print(result);

在我编码的时候,其他人提出了主要想法