如果该行或列包含 0,则将矩阵中的每个单元格设置为 0
给定一个包含 0 和 1 的 NxN 矩阵。 将包含 0
的每一行设置为全部 0
,并将包含 0
的每一列设置为全部 0
s。
例如,
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1
一位微软工程师
0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0
告诉我,有一个解决方案不涉及额外的内存,只需要两个布尔变量和一次传递,所以我正在寻找这个答案。
顺便说一句,假设它是一个位矩阵,因此矩阵中只允许包含 1 和 0。
Given a NxN matrix with 0s and 1s. Set every row that contains a 0
to all 0
s and set every column that contains a 0
to all 0
s.
For example
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1
results in
0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0
A Microsoft Engineer told me that there is a solution that involves no extra memory, just two boolean variables and one pass, so I'm looking for that answer.
BTW, imagine it is a bit matrix, therefore just 1s and 0s are allow to be in the matrix.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
好吧,所以我很累,因为现在是凌晨 3 点,但我进行了第一次尝试,对矩阵中的每个数字恰好进行了 2 次传递,因此在 O(NxN) 中,并且它与矩阵的大小呈线性关系。
我使用第一列和第一行作为标记来了解只有 1 的行/列在哪里。 然后,有 2 个变量 l 和 c 来记住第一行/列是否也全为 1。
因此,第一遍设置标记并将其余部分重置为 0。
第二遍在行和列标记为 1 的位置设置 1,并根据 l 和 c 重置第一行/列。
我强烈怀疑我是否可以在一次传递中完成,因为开始的方块取决于最后的方块。 也许我的第二遍可以变得更有效率......
Ok, so I'm tired as it's 3AM here, but I have a first try inplace with exactly 2 passes on each number in the matrix, so in O(NxN) and it is linear in the size of the matrix.
I use 1rst column and first row as markers to know where are rows/cols with only 1's. Then, there are 2 variables l and c to remember if 1rst row/column are all 1's also.
So the first pass sets the markers and resets the rest to 0's.
The second pass sets 1 in places where rows and cols where marked to be 1, and resets 1st line/col depending on l and c.
I doubt strongly that I can be done in 1 pass as squares in the beginning depend on squares in the end. Maybe my 2nd pass can be made more efficient...
这不能一次性完成,因为单个位会以任何顺序影响其之前和之后的位。 IOW 无论你以什么顺序遍历数组,你稍后都可能会遇到 0,这意味着你必须返回并将之前的 1 更改为 0。
更新
人们似乎认为通过将 N 限制为某个值固定值(比如8)你可以解决这个问题是一次通过。 那么,a)没有抓住重点,b)不是原来的问题。 我不会发布一个关于排序的问题并期待一个以“假设你只想对 8 件事进行排序......”开头的答案。
也就是说,如果您知道 N 实际上限制为 8,那么这是一个合理的方法。我上面的回答回答了没有这种限制的原始问题。
This cannot be done in one pass since a single bit has an effect on bits before and after it in any ordering. IOW Whatever order you traverse the array in, you may later come accross a 0 which means you have to go back and change a previous 1 to a 0.
Update
People seem to think that by restricting N to some fixed value (say 8) you can solve this is one pass. Well that's a) missing the point and b) not the original question. I wouldn't post a question on sorting and expect an answer which started "assuming you only want to sort 8 things...".
That said, it's a reasonable approach if you know that N is in fact restricted to 8. My answer above answers the original question which has no such retriction.
所以我的想法是用最后一行/列中的值作为标志来指示相应列/行中的值是否全部为1。
使用之字形扫描遍历除最后一行之外的整个矩阵/柱子。 在每个元素中,您将最后一行/列中的值设置为其自身与当前元素中的值的逻辑与。 换句话说,如果您输入 0,则最终行/列将设置为 0。如果您输入 1,则仅当最终行/列中的值已为 1 时,该值才会为 1。 无论如何,将当前元素设置为 0。
完成后,如果相应的列/行填充了 1,则最后的行/列应该有 1。
对最后一行和最后一列进行线性扫描并查找 1。 将矩阵体中最后一行和列都为1的相应元素设置为1。
编码它会很棘手,以避免差一错误等,但它应该一次性工作。
So my idea is to use the values in the last row/column as a flag to indicate whether all of the values in the corresponding column/row are 1s.
Using a Zig Zag scan through the entire matrix EXCEPT the final row/column. At each element, you set the value in the final row/column as to the logical AND of itself with the value in the current element. In other words, if you hit a 0, the final row/column will be set to 0. If you it a 1, the value in the final row/column will be 1 only if it was 1 already. In any case set the current element to 0.
When you've finished, your final row/column should have 1s iff the corresponding column/row was filled with 1s.
Do a linear scan through the final row and column and looking for 1s. Set 1s in the corresponding elements in body of the matrix where the final row and column are both 1s.
Coding it will be tricky to avoid off-by-one errors etc but it should work in one pass.
我在这里有一个解决方案,它在一次传递中运行,并且“就地”执行所有处理,没有额外的内存(除了增加堆栈)。
它使用递归来延迟零的写入,这当然会破坏其他行和列的矩阵:
I've got a solution here, it runs in a single pass, and does all processing "in place" with no extra memory (save for growing the stack).
It uses recursion to delay the writing of zeros which of course would destroy the matrix for the other rows and cols:
我认为这是不可能的。 当您位于第一个方格且其值为 1 时,您无法知道同一行和同一列中的其他方格的值是多少。 所以你必须检查这些,如果有零,则返回到第一个方块并将其值更改为零。 我建议分两遍进行 - 第一遍收集有关哪些行和列必须清零的信息(该信息存储在数组中,因此我们使用一些额外的内存)。 第二遍更改值。 我知道这不是您正在寻找的解决方案,但我认为这是一个实用的解决方案。 你给出的约束使问题无法解决。
I don't think it's doable. When you're on the first square and its value is 1, you have no way of knowing what the values of the other squares in the same row and column are. So you have to check those and if there's a zero, return to the first square and change its value to zero. I'll recommend doing it in two passes - the first pass gathers information about which rows and columns must be zeroed out (the information is stored in an array, so we're using some extra memory). The second pass changes the values. I know that's not the solution you're looking for, but I think it's a practical one. The constraints given by you render the problem unsolvable.
我可以使用两个整数变量和两次传递(最多 32 行和列...)
I can do it with two integer variables and two passes (up to 32 rows and columns...)
该问题可以一次性解决,
将矩阵保存在 i X j 数组中。
现在将 a 和 b 中保存的 i 和 j 的值打印为 0
其余值为 1,即 (3,3) (3,4) (5,3) 和 (5,4)
the problem can be solved in one pass
saving the matrix in an i X j array.
now print all values as 0 for values of i and j saved in a and b
rest of the values are 1 ie (3,3) (3,4) (5,3) and (5,4)
另一个需要两次传递的解决方案是水平和垂直累积 AND:
我想我可以使用 奇偶校验位、汉明码或动态编程,可能使用这两个布尔值作为2位数字,但我还没有成功。
您能否与您的工程师重新检查问题陈述并告知我们? 如果
确实有一个解决方案,我想继续解决这个问题。
Another solution that takes two passes, is to accumulate ANDs horizontally and vertically:
I thought I could design such an algorithm using parity bits, Hamming codes or dynamic programming, possibly using those two booleans as a 2-bit number, but I've had no success yet.
Can you please re-check the problem statement with your engineer and let us know? If
there is indeed a solution, I want to keep chipping away at the problem.
保留一个变量来跟踪所有行 AND 组合在一起的内容。
如果一行是 -1(全 1),则使下一行成为对该变量的引用。
如果一行不是 -1,则它是 0。您可以一次完成所有操作。 伪代码:
应该可以在一次传递中完成——但是这里有一个假设,即 N 足够小,CPU 可以在单行上进行算术运算,否则您将需要循环每一行以我相信,确定它是否全为 1。 但考虑到你问的是算法而不是限制我的硬件,我会以“构建一个支持 N 位算术的 CPU...”开始我的回答,
这是一个如何在 C 中完成它的示例。注意我认为Values 和 arr 一起代表数组,p 和 numproduct 是我的迭代器和 AND 产品变量,用于实现该问题。 (我可以用指针算术循环 arr 来验证我的工作,但一次就足够了!)
这会产生 0, 0, 6, 0, 6,这是给定输入的结果。
或者在 PHP 中,如果人们认为我在 C 中的堆栈游戏是作弊的(我建议你事实并非如此,因为我应该能够以我喜欢的方式存储矩阵):
我是否遗漏了一些东西?
Keep a single variable to keep track of what all of the rows ANDed together are.
If a row is -1 (all 1s), then make the next row a reference to that variable
If a row is anything but, it's a 0. You can do everything in one pass. Psuedo-code:
That should do it, in a single pass -- but there is an assumption here that N is small enough for the CPU to do arithmetic on a single row, else you're going to need to loop over each row to determine if it's all 1s or not, I believe. But given you're asking about algos and not constraining my hardware, I would just start my answer with "Build a CPU that supports N-bit arithmetic..."
Here's one example how it can be done in C. Note I argue that values and arr taken together represent the array, and p and numproduct are my iterator and AND product variables use to implement the problem. (I could have looped over arr with pointer arithmetic to validate my work, but once was enough!)
This produces 0, 0, 6, 0, 6, which is the result for the given inputs.
Or in PHP, if people think my stack games in C are cheating (I suggest to you that it's not, because I should be able to store the matrix whichever way I please):
Am I missing something?
很好的挑战。 该解决方案仅使用在堆栈上创建的两个布尔值,但由于该函数是递归的,因此在堆栈上创建了多次布尔值。
它以如下模式进行扫描:
等
,然后在每个扫描函数返回时更改此模式中的值。 (自下而上):
等等
Nice challange. This solution sort of uses just two booleans created on the stack, but the booleans are created several times on the stack since the function is recursive.
This scans in a pattern like:
and so on
And then changeing the values in this pattern on return on each of the scan functions. (Bottom up):
and so on
好吧,这是一种解决方案,它
Okay this is a solution that
实际上。 如果您只想运行算法并打印出结果(即不恢复它们),那么这可以轻松地一次性完成。当您在运行算法时尝试修改数组时,麻烦就来了。
这是我的解决方案 它只涉及对给定 (i,j) 元素的行/列值进行 AND 运算并将其打印出来。
Actually. If you just want to run the algorithm and print out the results (i.e. not restore them, then this can easily be done in one pass. The trouble comes when you try to modify the array as you're running the algorithm.
Here is my solution It just involves ANDing the rows/columns values for a givein (i,j)'s element and printing it out.
我尝试用 C# 解决这个问题。
除了实际矩阵和代表其维度的 n 之外,我还使用了两个循环变量(i 和 j)
我尝试的逻辑是:
代码:
I tried to solve this problem in C#.
I've used two loop variables (i and j) apart from the actual matrix and n representing its dimension
Logic I tried is to:
Code:
一次通过 - 我只遍历了一次输入,但使用了一个新数组和两个额外的布尔变量。
One Pass - I have traversed the input only once but used a new array and only two extra Boolean variables.
虽然在限制条件下不可能,但最有效的空间方法是以重叠、交替的行/列方式遍历矩阵,这将形成类似于以锯齿形方式砌砖的图案:
使用这个,您可以按照指示进入每一行/列,如果您在任何时候遇到 0,请设置一个布尔变量,然后重新遍历该行/列,将条目设置为 0。
这不需要额外的内存,并且只使用一个布尔变量。 不幸的是,如果“远”边全部设置为 0,这是最坏的情况,您将遍历整个数组两次。
While impossible given the constraints, the most space efficient way to do it is by traversing the matrix in an overlaping, alternating row/column fashion, which would make a pattern similar to laying bricks in a zig-zag fashion:
Using this, you would go in each row/column, as indicated, and if you encounter a 0 at any time, set a boolean variable, and re-walk that row/column, setting the entries to 0 as you go.
This will require no extra memory, and will only use one boolean variable. Unfortunately, if the "far" edge is set to all be 0, that is the worst case and you walk the whole array twice.
创建一个结果矩阵并将所有值设置为 1。
遍历数据矩阵,遇到 0 时,将结果矩阵行列设置为 0。
第一遍结束时,结果矩阵将得到正确答案。
看起来很简单。 我缺少什么技巧吗? 不允许使用结果集吗?
编辑:
看起来像 F# 函数,但这有点作弊,因为即使您只执行一次传递,该函数也可以是递归的。
面试官似乎想了解你是否了解函数式编程。
create a result matrix and set all the values to 1.
go through the data matrix as soon as a 0 is encountered, set the result matrix row column to 0
At the end of the first pass, the result matrix will have the correct answer.
Looks pretty simple. Is there a trick I am missing? Are you not allowed to use a result set?
EDIT:
Looks like a F# function, but that is cheating a bit since even though you are doing a single pass, the function can be recursive.
It looks like the interviewer is trying to figure out if you know functional programming.
好吧,我想出了一个使用 4 个布尔值和 2 个循环计数器的单遍就地(非递归)解决方案。 我没有设法将其减少到 2 个布尔值和 2 个整数,但如果这是可能的,我不会感到惊讶。 它对每个单元进行大约 3 次读取和 3 次写入,并且应该是 O(N^2) 即。 与数组大小呈线性关系。
我花了几个小时才弄清楚这个问题——我不想在采访的压力下想出这个问题! 如果我做了一个布布,我太累了,无法发现它......
嗯......我选择将“单遍”定义为对矩阵进行一次扫描,而不是一次接触每个值! :-)
Well, I came up with a single-pass, in-place (non-recursive) solution using 4 bools and 2 loop counters. I've not managed to reduce it to 2 bools and 2 ints, but I wouldn't be surprised if it was possible. It does around 3 reads and 3 writes of each cell, and it should be O(N^2) ie. linear in the array size.
Took me a couple of hours to puzzle this one out - I wouldn't want to have to come up with it under the pressure of an interview! If I've made a booboo I'm too tired to spot it...
Um... I'm choosing to define "single-pass" as making one sweep through the matrix, rather than touching each value once! :-)
我希望你喜欢我的 1-pass C# 解决方案,
你可以用 O(1) 检索一个元素,并且只需要
矩阵的一行一列的空间
i hope you enjoy my 1-pass c# solution
you can retrieve an element with O(1) and only need
the space of one row and one column of the matrix
1 次传递,2 个布尔值。 我只需假设迭代中的整数索引不计算在内。
这不是一个完整的解决方案,但我无法通过这一点。
如果我只能确定 0 是原始 0 还是转换为 0 的 1,那么我就不必使用 -1,这样就可以了。
我的输出是这样的:
我的方法的独创性是使用行或列检查的前半部分来确定它是否包含 0,并使用后半部分来设置值 - 这是通过查看 x 和宽度来完成的 -每次迭代中先是 x,然后是 y 和高度 y。 根据迭代前半部分的结果,如果在行或列中找到 0,我会使用迭代的后半部分将 1 更改为 -1。
我刚刚意识到这可以只用 1 个布尔值将 1 留给...来完成?
我发布这个希望有人会说,“啊,就这样做......”(我花了太多时间才不发布。)
这是 VB 中的代码:
1 pass, 2 booleans. I just have to assume the integer indexes in the iterations don't count.
This is not a complete solution but I can't get pass this point.
If I could only determine if a 0 is an original 0 or a 1 that was converted to a 0 then I wouldn't have to use -1's and this would work.
My output is like this:
The originality of my approach is using the first half of the examination of a row or column to determine if it contains a 0 and the last half to set the values - this is done by looking at x and width-x and then y and height-y in each iteration. Based on the results of the first half of the iteration, if a 0 in the row or column was found, I use the last half of the iteration to change the 1's to -1's.
I just realized this could be done with only 1 boolean leaving 1 to ...?
I'm posting this hoping someone might say, "Ah, just do this..." (And I spent way too much time on it not to post.)
Here's the code in VB:
没有人使用二进制形式吗? 因为它只有 1 和 0。我们可以使用二进制向量。
这是测试:
和输出:
No one is using binary forms? since it's only 1 and 0. We can use binary vectors.
Here's the test:
And the output:
您可以执行类似的操作来使用一次传递但使用输入和输出矩阵:
其中
col(xy)
是包含点xy
的列中的位;row(xy)
是包含点xy
的行中的位。n
是矩阵的大小。然后只需循环输入即可。 是否可以扩展以提高空间效率?
You can do something like this to use one pass but an input and output matrix:
where
col(xy)
is the bits in the column containing the pointxy
;row(xy)
is the bits in the row containing the pointxy
.n
is the size of the matrix.Then just loop over the input. Possibly expandable to be more space efficient?
一次矩阵扫描,两个布尔值,无递归。
如何避免第二次通过?
当零出现在行或列末尾时,需要第二遍来清除行或列。
不过这个问题是可以解决的,因为当我们扫描行 #i 时,我们已经知道行 #i-1 的行状态。 因此,当我们扫描行 #i 时,如果需要,我们可以同时清除行 #i-1。
相同的解决方案适用于列,但我们需要同时扫描行和列,而下一次迭代不会更改数据。
需要两个布尔值来存储第一行和第一列的状态,因为它们的值在算法主要部分的执行过程中会发生变化。
为了避免添加更多布尔值,我们在矩阵的第一行和第一列中存储行和列的“清除”标志。
One matrix scan, two booleans, no recursion.
How to avoid the second pass?
The second pass is needed to clear the rows or columns when the zero appeares at their end.
However this problem can be solved, because when we scan row #i we already know the row status for the row #i-1. So, while we are scanning the row #i we can simultaneously clear the row #i-1 if it is needed.
The same solution works for columns, but we need to scan rows and columns simultaneously while the data is not changed by the next iteration.
Two booleans are required to store the status of first row and first column, because their values will be changed during the execution of main part of the algorithm.
To avoid adding more booleans we are storing the "clear" flag for the rows and columns in the first row and column of the matrix.
似乎以下内容没有额外的空间要求:
首先请注意,将行的元素乘以元素所在行的元素,给出所需的值。
为了不使用任何额外的空间(不创建新矩阵并填充它,而是直接对矩阵应用更改),从矩阵的左上角开始并对任何 ixi 矩阵进行计算(“开始”于 (0 ,0)) 在考虑具有任何索引 > 的任何元素之前 我。
希望这有效(还没有测试)
seems like the following works with no additional space requirements:
first note that multiplying the elements of the row times the elements of the line in which an element is, gives the desired value.
In order not to use any additional space (not making a new matrix and filling it up but instead apply changes to the matrix directly), start top left of the matrix and do the computation for any ixi matrix (that "starts" at (0,0)) before considering any element with any index > i.
hope this works (havent testet)
这是针对 C++ 中不同 N 的测试,并且是:
一次通过、两个布尔值、无递归、无额外内存、保留任意大的 N< /strong>
(到目前为止,这里没有一个解决方案可以完成所有这些。)
更具体地说,我很有趣两个循环计数器是可以的。 我有两个 const unsigneds,它们仅存在而不是每次为了可读性而计算。 外循环的区间为[0, N],内循环的区间为[1, n - 1]。 switch 语句在循环中的存在主要是为了非常清楚地表明它实际上只是一次传递。
算法策略:
第一个技巧是从矩阵本身中获取一行和一列来累积矩阵的内容,通过从第一行卸载我们真正需要知道的所有内容,该内存变得可用列成两个布尔值。 第二个技巧是通过使用子矩阵及其索引的对称性来一次完成两次。
算法概要:
模板化 C++ 实现:
This is TESTED for different N in C++, and is:
ONE PASS, TWO BOOLS, NO RECURSION, NO EXTRA MEMORY, HOLDS FOR ARBITRARLY LARGE N
(So far none of the solutions here do ALL of these.)
More specifically, I'm amusing two loop counters are okay. I have two const unsigneds, which only exist rather than being computed every time for readability. The outer loop's interval is [0, N], and the inner loop's interval is [1, n - 1]. The switch statement is in the loop mostly exists to show very clearly that it really is just one pass.
Algorithm Strategy:
The first trick is to us a row and a column from the matrix itself to accumulate the content of the matrix, this memory becomes available by offloading all we really need to know from the first row and column into two booleans. The second trick is to get two passes out of one, by using the symmetry of the sub-matrix and its indices.
Algorithm Synopsis:
Templatized C++ Implementation:
好吧,我意识到这不太匹配,但我使用一个布尔值和一个字节而不是两个布尔值一次性得到了它......关闭。 我也不保证它的效率,但这些类型的问题通常需要低于最佳的解决方案。
Ok, I realize that it isn't quite a match, but I got it in one pass using a bool and a byte instead of two bools... close. I also wouldn't vouch for the efficiency of it but these types of questions often require less than optimal solutions.
你可以一次性完成它——如果你不计算以随机访问顺序访问矩阵,这消除了首先执行单次传递的好处(缓存一致性/内存带宽)。
[编辑:简单,但已删除错误的解决方案]
通过分两遍进行操作,您应该比任何单遍方法获得更好的性能:一次用于累积行/列信息,另一次用于应用它。 数组(按行优先顺序)被连贯地访问; 对于超过缓存大小(但其行可以放入缓存)的数组,应从内存中读取数据两次,并存储一次:
You can sorta do it in one pass -- if you don't count accessing the matrix in random-access order, which eliminates the benefits of doing it single-pass in the first place (cache-coherence/memory-bandwidth).
[edit: simple, but wrong solution deleted]
You should get better performance than any single-pass method by doing it in two passes: one to accumulate row/column info, and one to apply it. The array (in row-major order) is accessed coherently; for arrays exceeding the cache size (but whose rows can fit in cache), data should be read from memory twice, and stored once:
我能想到的最简单的解决方案粘贴在下面。 逻辑是记录迭代时将哪一行和哪列设置为零。
The simplest solution I can think of is pasted below. The logic is to record which row and column to set zero while iterating.
这是我的 Ruby 实现,其中包含测试,这将占用 O(MN) 空间。 如果我们想要实时更新(比如当我们找到零时显示结果,而不是等待找到零的第一个循环),我们可以创建另一个类变量,例如
@output
,并且每当我们找到零时我们更新@output
而不是@input
。Here is my Ruby implementation with the the test included, This would take O(MN) space. If we want a real time update (like to show the results when we find zeros rather than waiting the first loop of finding zeros) we can just create another class variable like
@output
and whenever we find a zero we update@output
and not@input
.下面的代码创建一个大小为 m,n 的矩阵。 首先确定矩阵的维度。 我想用 0..10 之间的数字随机填充矩阵[m][n]。 然后创建另一个相同维度的矩阵并用 -1 填充(最终矩阵)。 然后迭代初始矩阵,看看是否会命中 0。当命中位置(x,y) 时,转到最终矩阵,并用 0 填充 x 行,用 0 填充 y 列。
最后读取最终矩阵,如果值为-1(原始值),则将初始矩阵相同位置的值复制到最终矩阵。
The code below creates a matrix of size m,n. First decide the dimensions of the matrix. I wanted to fill the matrix[m][n] with randomly with numbers between 0..10. Then create another matrix of the same dimensions and fill it with -1s (final matrix). Then iterate through the initial matrix to see if you will hit 0. When you hit on location(x,y), go to the final matrix and fill the row x with 0s and column y with 0s.
At the end read through the final matrix, if the value is -1 (original value) copy the value in the same location of the initial matrix to final.
这是我的解决方案。 正如您从代码中看到的,给定一个 M * N 矩阵,一旦检查到该行中的零,它就会将该行设置为零。我的解决方案的时间复杂度是 O(M * N) 。
我正在共享整个类,其中有一个用于测试的静态填充数组和一个显示数组方法以在控制台中查看结果。
}
here is my solution. As you can see from the code, given a M * N matrix, it sets the entire row to zero once it inspects a zero in that row.the time complexity of my solution is O(M * N) .
I am sharing the whole class which has a static populated array for testing and a display array method to see the result in the console.
}