我们可以在少于o(n*n)的情况下计算一下……(nlogn或n)
-
01-10-2019 - |
题
这是一个非常著名的跨国公司向我问的问题。问题如下...
输入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)。