【问题标题】:Get the number of distinct elements in a submatrix获取子矩阵中不同元素的数量
【发布时间】:2014-01-10 16:43:35
【问题描述】:

这是a problem from the December 2013 CodeChef Challenge,比赛已经结束。

问题陈述:

输入: n 阶方阵和表示子矩阵的查询。

(x1, y1, x2, y2)

x1, y1 表示左上角,x2, y2 表示子矩阵的右下端。

输出:此子矩阵中不同元素的数量。

约束:

  • 时间限制 = 1 秒
  • 1≤N≤300
  • 1≤Q≤10^5
  • 1≤Ai,j≤10
  • 1≤X1≤X2≤N​​i>
  • 1≤Y1≤Y2≤N​​i>

这是我尝试过的:

#include<stdio.h>
//#include<conio.h>
int main()
{
  //clrscr();
  int a[300][300], test[100000], count[10], m, n, c, j, p, q, r, s;
  long qu, re, i;

  scanf("%d", &n);

  for (i = 0; i < n; i++)
  {
    for (j = 0; j < n; j++)
    {
      scanf("%d", &a[i][j]);
    }
  }

  scanf("%ld", &qu);
  for (re = 0; re < qu; re++)
  {
    c = 0;
    for(i = 0; i < 10; i++)
    {
      count[i] = 0;
    }

    scanf("%d %d %d %d", &p, &q, &r, &s);
    for (i = (p-1); i < r; i++)
    {
      for (j = (q-1); j < s; j++)
      {
        m = a[i][j];
        count[--m]++;
      }
    }

    for (i = 0; i < 10; i++)
    {
      if (count[i] != 0)
      {
        c++;
      }
    }
    test[re] = c;
  }

  for(i = 0; i < qu; i++)
  {
    printf("%d\n", test[i]);
  }

  //getch();
  return 0;
}

但我收到了 TLE(超出时间限制)错误。

它必须与每个数字的累积频率有关。

有人可以为这个问题提出一个有效的算法吗?

【问题讨论】:

  • 您的代码应适当缩进,以便我们阅读。此外,您应该使用更有意义的变量名,而不是一两个字母的变量名。
  • 您似乎假设矩阵仅包含整数 0 到 9。但这在您的问题中没有说明!

标签: c arrays algorithm distinct-values


【解决方案1】:

初始化并跟踪哈希映射。

遍历子矩阵的条目,并且对于每个条目,

  • 检查它是否已经在哈希映射中;
  • 如果不是,则将 total_distinct_entries 加 1,并将此条目添加到哈希映射中。

http://en.wikipedia.org/wiki/Hash_table

编辑:另见http://en.wikipedia.org/wiki/Set_data_structure,特别是关于实现的部分。在 C++ 中,标准库中提供了 std::set 数据结构。

【讨论】:

  • 哈希映射实际上比 OP 当前的效率。请注意,问题中的代码仅循环通过目标区域一次,执行 2 行非常简单的代码。
  • @Dukeling 没错; OP 的“解决方案”假定矩阵条目在[1,10] 范围内,他在原始帖子中没有说明。我同意他的解决方案品牌比带有这个附加约束的哈希映射更快,但是有了这个附加约束,似乎真的没有比他拥有的解决方案更好的解决方案了,除了......
  • (续)...看起来(从他的解决方案向后阅读)问题在于他将得到一些 collection 的子矩阵 相同的矩阵,并且期望他优化解决方案的方式是在迭代之间缓存信息。当然,在他的问题描述中没有提到任何这些。
【解决方案2】:

已编辑

(使用 1 个基于索引的索引)

第一次尝试:

执行蛮力,将每个数字的计数存储在问题发布者给出的计数数组中,但这肯定会在很多测试用例中超时。

第二: 由于我们知道条目最多只能是 10 我们可以尝试存储每个数字在子矩阵 (1,1) 到 (i,j) 中出现的次数。 假设这个矩阵是 Q。Q[i][j][k] 给出了 k 在 i,j 子矩阵中出现的次数。

这可以有效地计算如下:

for i from 1 to n
    for j from 1 to n
       for k from 0 to 10
            Q[i][j][k] = Q[i-1][j][k] + Q[i][j-1][k] - Q[i-1][j-1][k]
       Q[i][j][A[i][j]]++

这可以在 O(n^2 * (k)) 时间内完成。由于 k 小于 10,因此非常有效。

现在回答问题很容易:

对于一个查询 (x1,y1) - (x2,y2)

int count[10]
for k from 0 to 10
   // x is row and y is column
   count[k] = Q[x2][y2][k] - Q[x1-1][y2][k] - Q[x2][y1-1][k] + Q[x1-1][y1-1][k]

这会在 O(k) 时间内回答所有查询。因为 k 是从 0 到 10。它在时间限制之内。

【讨论】:

  • @gustav-bertram 这里没有假设,我不想为他破坏整个问题。 codechef.com/viewsolution/3102585
  • 由于原始发布者的解决方案没有针对N=300 Q=100000 (X1,Y1,X2,Y2)=(1,1,300,300) 输入进行充分优化,您介意发布您的解决方案以及它是如何工作的吗?
  • 这是一个非常令人印象深刻的答案!谢谢您的发布。关于破坏问题 - 在 Stack Overflow 上,您不应该为懒惰的人他们做工作,但没有任何为某人破坏问题的概念。如果您可以轻松地完全回答问题,那么您应该这样做。它旨在帮助的不仅是最初的提问者,而且是今天之后阅读问题和答案的每个人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-02
  • 1970-01-01
  • 2014-01-04
  • 2020-11-14
  • 2018-12-13
  • 1970-01-01
相关资源
最近更新 更多