这是一个非常著名的跨国公司向我问的问题。问题如下...

输入0和1的2d n*n数组。如果a(i,j)= 1,则与ITH行相对应的所有值和jth列的相对应为1。如果已经有1个,则将其保留为1。

例如,如果我们有数组

  1 0 0 0 0 
  0 1 1 0 0 
  0 0 0 0 0 
  1 0 0 1 0
  0 0 0 0 0

我们应该将输出作为

 1 1 1 1 1
 1 1 1 1 1
 1 1 1 1 0
 1 1 1 1 1
 1 1 1 1 0

输入矩阵稀疏。

这可能在少于O(n^2)中吗?

没有其他空间是另一个条件。我想知道是否有一种方法可以使用空间<= o(n)实现复杂性。

PS:我不需要答案,使我变得复杂(n*n)。这不是作业问题。我已经尝试了很多,无法得到适当的解决方案,以为我可以在这里得到一些想法。将印刷品放在一边

我的粗略想法是可以动态地消除限制在2N左右的元素的数量。但是我没有一个正确的主意。

有帮助吗?

解决方案 7

嗨,家伙,

多亏了MB14的评论,我认为我可以在少于o的情况下得到解决(n)n)时间...最糟糕的情况会占用O(nn)...

实际上,我们有给定的数组

  1 0 0 0 1
  0 1 0 0 0 
  0 1 1 0 0 
  1 1 1 0 1
  0 0 0 0 0 

让我们有2个尺寸n的数组(这将是最坏的情况)...一个专门用于索引行和其他列...将那些带有[i] [1] = 0的人放在一个数组中,然后a [1 ] [j] = 0在另一个..

然后仅采用这些值,然后检查第二行和柱面...以这种方式,我们得到了只有0的行的行和柱面的值。

行阵列中的值数量给出了结果数组中的0数,并且[行阵列值] [列数组值]为您提供了这些点...。

我们可以在下面的下方解决它(nn)和最坏的是o(nn)...正如我们所能看到的,(尺寸n)的数组减小。

我这样做了几个数组,并为所有这些都取得了结果... :)

如果我在任何地方都错了,请纠正我...

thanx对于所有评论,大家...你们都非常有帮助,我确实在一路上学到了很多东西... :)

其他提示

在最坏的情况下,您可能需要从0到1切换n * n -n位才能生成输出。看来您被O(n*n)所困扰。

我想您可以为最好的情况对其进行优化,但是我很想说您最坏的情况仍然是O(n*n):最坏的情况将是所有0的数组,您必须检查每个元素。

优化将涉及一旦找到“ 1”(我可以提供详细信息,但您说您不在乎o(n*n)),但是除非您有元数据表明一个整个行/列是空的,或者除非您有一种SIMD风格的方式一次检查多个字段(例如,如果每个行都按4对齐,则可以读取价值32位的数据,或者您的数据以一个bitmask),您将始终必须处理全零数组的问题。

显然,也不必须稀疏输出矩阵或否定版本(将第一行设置为1的一半,而其他任何内容均为0),因此时间取决于您允许您用于输出的格式。 (我假设输入是元素或等效元素的列表,因为否则您无法利用矩阵稀疏。)

O(m+n)空间和时间的简单解决方案(m是输入矩阵中的数量):取两个长度为n的阵列,填满了n的长度n,遍历输入中的所有阵列,每个滴度x从第一个数组和第二个数组的Y坐标。输出是两个阵列,它清楚地定义了结果矩阵:它的(x,y)坐标为0,如果第一个数组的x坐标为0,则第二个阵列的x坐标为0,第二个数码为0。

更新: 根据语言,您可以通过多次引用同一行来返回普通的2D数组。例如,在PHP中:

// compute N-length arrays $X and $Y which have 1 at the column 
// and row positions which had no 1's in the input matrix
// this is O(M+N)
$result = array();
$row_one = array_fill(0,N,1);
for ($i=0; $i<N; $i++) {
    if ($Y[$i]) {
         $result[$i] = &$row_one;
    } else {
         $result[$i] = &$X;
    }
}
return $result;

当然,只要您不尝试编写它,这是一个正常的数组。

由于必须检查矩阵的每个条目,因此最坏的情况始终为n*n。

使用额外的2*n额外存储,您可以在O(n*n)中执行操作。只需为每一行创建一个掩码,并为每列创建一个掩码 - 扫描数组并在您使用时更新掩模。然后再次扫描以基于掩模填充结果矩阵。

如果您要在更改输入矩阵的地方进行操作,则可以为输入的每一行和列存储一个非零条目计数(而不是简单的掩码)。然后,当输入中的条目更改时,您可以相应地更新计数。到那时,我将完全删除输出矩阵,并直接查询掩码/计数,而不是维护输出矩阵(当事物在少于n的情况下变化时也可以更新n如果您真的想保留它)。因此,加载初始矩阵仍然是O(nn)但是更新可能会少得多。

输入矩阵可能很少,但是除非您可以以稀疏格式获得它(即 (i,j) 最初设置的对),只需读取输入即可消耗ω(n^2)时间。即使输入稀疏,也很容易获得O(n^2)输出。作为作弊,如果允许您输出设定的行和设置列的列表,则可以到达线性时间。当您的算法实际上必须产生比“是”或“否”更为实质的结果时,就没有魔力了。

麦道埃拉(McDowella)对另一个答案的评论暗示了另一种替代输入格式:运行长度编码。对于稀疏输入,显然不需要O(n)时间才能读取它(考虑0和1之间有多少个过渡)。但是,从那里崩溃了。考虑构成如下的输入矩阵:

0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 . . . 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . . .
.     .
.       .
.         .

也就是说,在第一行中交替0和1,其他任何地方都有0。显然很少,因为有 n/2 总共。但是,RLE输出必须在每一行中重复此模式,从而导致O(n^2)输出。

你说:

我们应该将输出作为...

因此,您需要输出具有n^2元素的整个矩阵。这是O(n*n)。

问题本身不是o(n*n):您不必计算和存储整个矩阵:您只需要两个向量,即l和c,每个矩阵大小n:

l [x]为1,如果线x是一条线,否则为0;

C [X]为1,如果线X是一条线,否则为0;

您可以在O(n)中构造这些向量,因为初始矩阵稀疏。您的输入数据将不是矩阵,而是包含每个非零元素的坐标(线,列)的列表。在阅读此列表时,您将l [line] = 1和c [列] = 1设置,并且解决了问题:m [l,c] == 1如果l [l] == 1或c [c] = = 1

显然有 O(N^2) 要做的工作。在矩阵中

1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1

所有位必须设置为1,并且 N*(N-1) 未设置为一个(在此5x5情况下20)。

相反,您可以提出一种总是在 O(N^2) 时间:沿顶行和列总和,如果行或列获得非零答案,请填写整个行或列;然后解决较小的(N-1)X(N-1)问题。

因此,存在至少必须采取的案件 N^2 任何情况都可以解决 N^2 没有额外的空间。

如果您的矩阵稀疏,则复杂性很大程度上取决于输入编码,尤其是在NN中测得的不当2 或类似的东西,但就您的输入复杂性而言 您的输出复杂性m出去. 。我期待像O(N + M + m出去),但取决于编码和您可以使用的技巧。

这完全取决于您的输入数据结构。如果将矩阵(1s和0s)作为2D数组传递,则需要穿越它,即O(n^2)。但是,由于数据稀疏,如果您仅通过1作为输入,则可以这样做,以便ouptut为o(m),其中m不是单元格的数量,而是1个单元的数量。这将与此类似(下面的伪代码):

list f(list l) {
   list rows_1;
   list cols_1;

    for each elem in l {
        rows_1[elem.row] = 1;
        cols_1[elem.col] = 1;
    }

    list result;
    for each row in rows_1 {
        for each col in cols_1 {
             if (row == 1 || col == 1) {
                 add(result, new_elem(row, col));
             }
        }
    } 
   return result;
}

检查值时,请勿填充矩阵的中心。当您浏览元素时,当您有1个设置第一行中的相应元素和第一列。然后返回并填满。

编辑:实际上,这与安迪相同。

这取决于您的数据结构。

行只有两种可能的情况:

  • 如果输入中有一个元素(i,_)
  • 所有其他行都是相同的:即j-th元素是1 iff,输入中有一个元素(_,j)。

因此,结果可以紧凑地表示为对行的引用数组。由于我们只需要两行,因此结果也只会消耗O(n)内存。例如,这可以在Python中实现,如下所示:

def f(element_list, N):
  A = [1]*N
  B = [0]*N
  M = [B]*N
  for row, col in element_list:
    M[row] = A
    B[col] = 1
  return M

示例电话将是

 f([(1,1),(2,2),(4,3)],5)

结果

[[0, 1, 1, 1, 0], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [0, 1, 1, 1, 0], [1, 1, 1, 1, 1]]

重要的一点是,此处未复制阵列,即m [row] = a只是参考的分配。因此,复杂性为O(n+m),其中m是输入的长度。

#include<stdio.h>

包括

int main(){int arr [5] [5] = {{{1,0,0,0,0},{0,1,1,0,0},{0,0,0,0,0,0} ,{1,0,0,1,0},{0,0,0,0,0}}}; int var1 = 0,var2 = 0,i,j;

for(i=0;i<5;i++)
   var1 = var1 | arr[0][i];

for(i=0;i<5;i++)
   var2 = var2 | arr[i][0];

for(i=1;i<5;i++)
   for(j=1;j<5;j++)
      if(arr[i][j])
         arr[i][0] = arr[0][j] = 1;

for(i=1;i<5;i++)
   for(j=1;j<5;j++)
          arr[i][j] = arr[i][0] | arr[0][j];

for(i=0;i<5;i++)
   arr[0][i] = var1;

for(i=0;i<5;i++)
   arr[i][0] = var2;

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

getch();

}

该程序仅利用2 4个临时变量(VAR1,VAR2,I和J),因此在恒定空间中运行,随时间复杂性o(n^2)。我认为在<<<< o(n^2)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top