【问题标题】:Find all number pairs in a given range查找给定范围内的所有数字对
【发布时间】:2015-07-28 09:39:54
【问题描述】:

我有 N 个号码,比如说20 30 15 30 30 40 15 20。现在我想找出给定范围内有多少对数字。(L 和 R 给出)。 数字对=两个数字相同。 我的做法:

创建一个数组映射,使得 映射的键=数字,值=该数字出现的索引的数组列表。然后我从 L 遍历到 R 并且对于该范围内的每个值,我在相应的数组列表中遍历以查找是否存在适合范围的对,然后递增计数。

但我认为这种方法太慢了。有没有更快的方法来做同样的事情?

示例:对于上面给定的序列和 L=0 和 R=6 答案=5。可能的配对是 20 的 1、15 的 1 和 30 的 3。

我正在开发一个解决方案,假设数字可以达到 10^8(并且非负数)。

【问题讨论】:

  • 其实我的想法和你一模一样!我认为这是最简单快捷的方法。
  • 如果你用数组来计算一个元素重复了多少次,它会比映射消耗更多的大小和时间。
  • 我可以将数组用于小整数。但是如果数字大于 10^7 会怎样。
  • 这就是我的意思。我的东西映射是最快的方法。当我尝试在 ACM 等竞争性竞赛中解决问题时,我首先想到的是地图!不会浪费内存和时间。

标签: algorithm array-algorithms


【解决方案1】:

如果您正在寻找速度并且不关心内存,那么也许有更好的方法。

您可以使用集合作为辅助数据结构来查看是否找到了一个数字,然后简单地遍历数组。伪代码:

int numPairs = 0;
set setVisited;
for (int i = L; i < R; i++) {
  if (setVisited.contains(a[i])) {
    // found the second of a pair. count it up and reset.
    numPairs++;
    setVisited.remove(a[i]);
  } else {
    // remember that we saw this number, so we can spot the next pair.
    setVisited.add(a[i]);
}

【讨论】:

  • 但在示例中,三个 30s 算作三对。您的解决方案只会产生一个。
  • 它会找到所有 3。一旦找到第二个 30,numPairs 就会增加,并从集合中删除 30。当找到第 3 个 30 时,将其添加到集合中。当找到第 4 个 30 时,再次增加 numPairs,依此类推。
  • 没有第 4 个 30。让我们索引示例数组 {20, 30*, 15, 30**, 30***, 40, 15, 20} 中的三个 30 以区分它们。然后这三对是 {30*, 30**}, {30*, 30***} 和 {30**, 30***}。换句话说,如果一个数字在范围内出现 n 次,那么您可以构建的对数是 n! /2!
【解决方案2】:

新的解决方案...希望这次会更好。伪 C-ish 代码:

// Sort the sub-array a[L..R]. This can be done O(nlogn) using qsort.
// ... code omitted ...

// Walk through the sorted array counting how many times number occurs.
// When the number changes, count how many possibles ways to make pairs
// from the given count.
int totalPairs = 0;
int count = 1;
int current = a[L];
for (i = L+1; i < R; i++) {
  if (a[i] == current) { // found another, keep counting
    count++;
  } else { // found a different one
    if (count > 1) { // need at least 2 to make a pair!
      totalPairs += factorial(count) / 2;
    }
  }
  // start counting the new one
  current = a[i];
  count = 1;
}

// count the final one
if (count > 1) {
  totalPairs += factorial(count) / 2;
}

排序运行 O(nlgn),循环体运行 O(n)。有趣的是,性能障碍现在是因子。对于出现次数非常多的非常长的数组,除非您进一步优化,否则阶乘会很昂贵。

一种方法是循环计数重复但不计算阶乘——留下另一个数字计数数组。然后对这个数组进行排序(同样是 Nlg(N)),然后遍历这个数组并重新使用之前计算的阶乘来计算下一个。

此外,如果这个数组变大,您将需要一个大整数来表示总数。我不知道大整数的 O() 性能。

很酷的问题!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-23
    • 2014-04-27
    • 1970-01-01
    • 2020-10-03
    • 2020-02-29
    • 2019-12-31
    相关资源
    最近更新 更多