【问题标题】:What's an efficient algorithm to find one unique number in a set of 1 millions numbers? [closed]在一组 100 万个数字中找到一个唯一数字的有效算法是什么? [关闭]
【发布时间】:2014-01-06 08:25:45
【问题描述】:

我在一次采访中被问到这个问题。在 100 万个数字中,除了一个数字外,所有数字都有重复。如何找到那个号码?我应该使用哪种算法来获得良好的时间和空间复杂度?我有一个使用 EXOR 门的想法,但我在部署它时仍然滞后。

【问题讨论】:

  • 你走对了,你的问题到底是什么?向我们展示迄今为止的尝试?
  • @Angew:“有重复”并不意味着“正好有两个”,对吗?好吧,我想从字面意义上来说......(但不是堆栈溢出的意义!:-))
  • @KerrekSB 问题是“有 the 重复。”更不用说要使 XOR 起作用,每个重复项必须有偶数个。
  • 你对这些数字有什么了解吗?有符号/无符号,数据类型,它们是否以开头排序,它们都是以特定 N 开头的整数吗?
  • 始终牢记附加问题:找到两个唯一的数字。

标签: algorithm data-structures


【解决方案1】:

按顺序对所有数字使用xor

对于以下数字列表:

1, 2, 3, 4, 3, 2, 1

^代表排他析取(或xor

那么,
1 ^ 2 ^ 3 ^ 4 ^ 3 ^ 2 ^ 1 = 4

【讨论】:

  • 你应该添加一些解释,你的解决方案是正确的:)
  • System.out.println(1 ^ 1 ^ 2 ^ 3 ^ 3 ^ 3);打印 1
  • @EvgeniyDorofeev :显然2 ^ 31
  • 这只有在每个值出现偶数的情况下才有效,但我认为在这种情况下重复意味着“两个”
  • @MadHatter 但它应该是 2
【解决方案2】:

另一个简单的解决方案:可以使用两个位集,一个用于标记数字的存在,另一个用于标记重复。我们遍历数组并标记每个元素的存在和重复。然后我们遍历比特集以找到一个被标记为存在但没有被标记为重复的数字。

int[] numbers = new int[] { 1, 1, 2, 2, 3, 4, 4, 5, 5 };

    BitSet bs1 = new BitSet();
    BitSet bs2 = new BitSet();

    int largestNumber = 0;

    for (int i = 0; i < numbers.length; i++) {
        int number = numbers[i];
        if (bs1.get(number) == false) {
            // Mark for existence
            bs1.set(number);
        } else {
            // Mark for duplicating
            bs2.set(number);
        }

        if (number > largestNumber) {
            largestNumber = number;
        }
    }

    for (int i = 0; i <= largestNumber; i++) {
        if (bs1.get(i) && !bs2.get(i)) {
            System.out.println("Non duplicating number is:  " + i);
        }
    }

}

【讨论】:

  • 你增加了内存复杂度...
【解决方案3】:

试试这个

    int[] a = {1, 2, 1, 2, 3};
    Arrays.sort(a);
    for(int i = 0; i < a.length; i++) {
        if (i == 0 && a[i] != a[i + 1] || i == a.length -1 || a[i] != a[i - 1] && a[i] != a[i + 1]) {
            System.out.println(a[i]);
            break;
        }
    }

【讨论】:

  • 计算成本很高
  • 这会很昂贵,几乎 O(N) 将是从数字到出现的 HashMap
  • 这将花费很多时间.. 排序算法在列表 O(nlogn) 上占用,而您有 100 万...太多了
  • @TarekSalah 问题是百万。
  • @TarekSalah 百万并没有那么大,因为今天的计算机会在几毫秒内完成排序。我认为这是更可取的解决方案,因为像 X-OR 一样,它并不假设重复项是偶数
【解决方案4】:

以下可能会解决您的问题:

复杂度:O(N)

// Assuming the duplicate are going by pair
// x ^x == 0 and x ^0 == x
int find_unique(const std::vector<int>& v)
{
    assert(v.size() % 2 == 1);

    int res = 0;
    for (auto value : v) {
        res ^= value;
    }
    return res;
}

或者
复杂度:O(N log N)

int find_unique(std::vector<int>& v)
{
    if (v.empty()) { throw std::runtime_error("empty vector"); }
    std::sort(v.begin(), v.end());
    auto it = std::unique(v.begin(), v.end());
    if (it == v.begin()) { throw std::runtime_error("no unique number"); }
    if (it != v.begin() + 1) { throw std::runtime_error("several unique numbers"); }
    return v[0];
}

或 复杂度:O(N log N)

int find_unique(std::vector<int>& v)
{
    if (v.empty()) { throw std::runtime_error("empty vector"); }
    if (v.size() == 1) { return v[0]; }
    std::sort(v.begin(), v.end());
    if (v[0] != v[1]) { return v[0]; }

    for (int i = 1, size = v.size(); i + 1 < size; ++i) {
        if (v[i] == v[i - 1]) { continue; }
        if (v[i] == v[i + 1]) { ++i; continue; } // we may skip v[i + 1]
        return v[i];
    }
    return v.back();
}

【讨论】:

    【解决方案5】:

    我相信,如果我们结合快速排序(搜索)技术和异或,我们可以获得最快的代码。我正在尝试,但如果这个想法是错误的,请纠正我。

    顺便说一句,这有很多用例。虽然这个问题与语言无关,并且需要清晰的算法,但我提到了一些读者可能会觉得有用的用例。

    0 可以是重复的...或负数...

    System.out.println(33 ^ 33 ^ 7 ^ 0 ^ 0 ^ 5 ^ 7 ^ 5); 给出 0(0 在这里重复)

    重复可能超过 2 个:

    System.out.println(1 ^ 1 ^ 2 ^ 3 ^ 3 ^ 3); 给出的是 1,而不是 2...

    等等,这个问题可能比我们最初想象的要复杂。

    【讨论】:

      【解决方案6】:

      对于大量的输入项(与具有少量数字的示例相反),将输入输入到某些数据结构中需要相当长的时间。我正在考虑将这个必要的时间作为计算过程的一部分,将其放入地图中。地图的值将仅为一个数字。我假设数据是正确的,所以我省略了检查,但如果有多个数字只出现一次,它只会返回第一个。

      应该有进一步优化的空间,例如通过按值访问地图并查找具有 1 的地图。我认为这可以通过 Boost.Bimap 轻松完成。

      int getSingleNumber(){
      
      map<int, int> numbers;
      
      for (all input items)
          {
          numbers[currentInputItem]++;
          }
      
      for( map<int,int>::iterator ii=numbers.begin(); ii!=numbers.end(); ++ii)
      {
          if ( (*ii).second == 1 ) return (*ii).first;
      }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-29
        • 2015-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-14
        • 1970-01-01
        相关资源
        最近更新 更多