查找表示行sortingmatrix中的最小整数的行

在最近的Java电话采访中,我被问到了这个问题:

给你一个NxN二进制(0-1)matrix,它具有以下属性:

  • 每一行都被sorting(0的序列后跟1的序列)
  • 每行代表一个无符号整数(通过读取位)
  • 每一行都是唯一的

例:

0 1 1 1 1 1 0 0 1 

每行中的位值被sorting,行代表整数3,7和1。

find表示最小整数的行。 在上面的例子中,答案是第3行,代表整数1。

我开始用二次复杂的蛮力。 面试官回答说,我不是在利用已分类的财产。

想了很多,我在每一行使用二进制search,它来到O(nlogn)。 他问我能不能进一步改进。 我想了很多,但未能改善。

如果有任何人可以给予任何指示,我将不胜感激。

另一个例子:

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

答案将是第3行,代表整数0。

从第1行开始。向右走,直到你打到第1 。 然后下降到第2行,但保持在同一列,并重复正确的过程,直到你达到1 。 反复做这个。 你最后一个正确的行是你的答案。

这是一个O(N + M)解(对于一个N×Mmatrix,或者对于问题中给出的一个正方形N×Nmatrix的O(N))。

用你的例子:

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

. 这里代表着所走过的道路:

 . . 1 1 0 . . . 0 0 0 . . Last right step, therefore this is our answer 1 1 1 1 . 

该解决scheme在非方阵上工作,保持N×Mmatrix的最坏情况O(N + M)效率。

为什么这个工作? 保证数字将被sorting意味着每一行将是一系列的0,然后是一系列的1。 所以一行的大小等于你在打1之前可以走多远。所以如果一行可以通过跟随0来进一步取得,那么它必须比我们以前处理的任何东西都长。

Python代码:

 li = [[0, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 1, 1]] ans, j = 0, 0 for i, row in enumerate(li): while j < len(row) and row[j] == 0: j += 1 ans = i print "Row", ans+1, "".join(map(str, li[ans])) 

也有一个更简单的解决scheme,因为总是有一个正方形的N×Nmatrix和不同的行在一起的限制。 它们一起表示具有最低值的行将是0 0 ... 0 10 0 ... 0 0 。 这是因为在matrix中有N + 1个可能的数字,因此“缺失”数字可以是0(在这种情况下表示的最小值是1)或者是其他值(最小值是0)。

有了这些知识,我们从右边第二列检查一个0.当我们find一个,我们看右边,如果包含另一个0,我们有我们的答案(只能有一个行以0结尾)。 否则,我们继续在列中search另一个0.如果我们没有find另一个0,我们发现的第一个是我们正在查找的行(只能有一行以01结尾,因为没有结束在00 ,这是最小的)。

Python代码:

 li = [[0, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 1, 1]] for i, row in enumerate(li): if row[-2] == 0: ans = i if row[-1] == 0: break print "Row", ans+1, "".join(map(str, li[ans])) 

这个解决scheme在O(N)中以最小的难度回答了这个问题,但是将其推广到处理非平方N×Mmatrix或非不相关数字将使其最坏情况效率O(N ^ 2)。 我个人更喜欢第一个解决scheme。

最低的数字必须是0或1.(因为没有重复和行sorting)。 所有你需要做的是越过最后一列,如果ti包含0最低的数字是0否则最低的数字是1。

编辑 – 解释
N行中,您可以设置最多N+1唯一值。
所以肯定至less0或1必须在matrix….

编辑2 – algorithm

 //assuming the matrix is 0 indexed base for i = 0...N-1 if M[i][N-1] == 0 return "Value is 0 in row i"; for i = 0...N-1 if M[i][N-2] == 0 return "Value is 1 in row i"; //because of the explanation above the flow will never reach here. 

由于数字是唯一的,并且由于数字是分类的,所以很清楚,对于任何N值,最小的数字可以是[0(N-1次),后面是1]或0(N次) 。

例如,对于N = 4,最小的数字可以是0001或0000。

换句话说,我们希望find的数字的倒数第二位是0,最后一位数字可以是0或1

这个问题然后简化为只在数组中find这些模式,这可以使用一个简单的for循环来完成

 int rowNum = -1; for(int i=0;i<N;i++) { if(arr[i][N-2]==0) //Second last digit is 0. Hence the number could be min. { rowNum = i; if(arr[i][N-1]==1) // If number of the form 0001 was found, keep looking for 0000 { continue; } else //If number of the form 0000 was found, exit. //No other number can be lesser than 0000 { break; } } } return rowNum; 

这个algorithm会有复杂度O(n)

你想find最大数量的零的行。

  • arr[0][0]开始arr[0][0]
  • 如果它是0 ,检查右边的元素, arr[0][1]
  • 如果不是0则跳过该行,并开始检查当前元素下一行的元素。

继续做下去,直到你经过最后一行/最后一列,或者你find一个全零的行。

algorithm:

 i = 0 j = 0 answer = 0 # continue till i is a valid index. while(i<N) # continue till j is valid index and ele is 0. while(j < N AND arr[i][j] == 0) # move towards right. j++ #update answer. answer = i # found a row with all zeros. if(j == N) break all loops. end-if end-while # skip current row..continue on next row. i++ end-while print answer 

这个复杂度是O(N+N) ,它是O(N) ,即线性的。

Java实现

相关问题哪个使用完全相同的技巧

如何有效地search有序matrix?

 Start at the top-left. The first row is the best row so far. Repeat until you reach the bottom: If you're not already over a 1: Go right until you find a 1. This row is the best row so far. Go down one row. Report the best row that was found. 

你永远不会上升或离开 – 你只能下降(n-1)次,并且不超过(n-1)次,使得这个O(n)。 这利用sorting,意识到你永远不必离开去检查一个1 – 如果在左边某个地方有一个1,那么在当前地点也有一个1(因此这一行中的数字至less是与前一行一样大)。

由于每行中的位都被sorting,所以一旦find1位,右边的所有位也必须为1。 换句话说,数组只存储2 ^ n-1forms的值。

所以答案是最零的行是最小的。

但是,由于只有2 ** m-1个条目可以存在,并且有n个条目,并且没有两个是相同的,所以我们可以推导出更多 – 对于任何N,都有N + 1个这样的值。 所以0或1必须存在,因为我们知道没有重复。

所以寻找一个空行(这是只有一个最右边的列零)。 如果你找不到,答案是1,否则是0。

上)

如何循环每行倒序和检查1s结束和零开始?

实际上,在NxN保证最坏的情况是0不会在那里。 所以你可以检查每行的最后2个条目。 这使得它线性。

由于我的解释没有被理解,所以这里有些伪代码:

 int lowestRow = -1; for (k = 0; k < array.length; k ++) { byte[] row = array[k]; if (row[row.length - 1] == 0) { lowestRow = k; break; } if (row[row.length - 2] == 0) { lowestRow = k; //possibly look for all-zeroes, so not breaking } } 

您必须从最后一列开始,检查元素的总和是否为N-1,一旦findsum = N-1的列,search包含0的列,这就是您正在查找的列…

@codaddict的优化版本

 int best = N; int answer = -1; for(int i=0;i<N;i++) for(int j=0;j<best;j++) if (arr[i][j] != 0) { best = j; answer = i; } 

一旦它确定这行不会比当前的答案更好,内循环会停止。 这可能会削减大量search下行比迄今为止最好的答案。

在最远的列中查找哪一行具有第一个非零值。 如果它是二进制的,MSB在左边,LSB在右边,那么答案就是以零开始的那一行。

如果可以的话,我会加上这个作为对杰勒米答案的评论,因为他的解决scheme大多是正确的。 另外,我喜欢这个方法。 在许多情况下,这将比其他答案快得多。 有一个可能的问题。 如果“每行都sorting”。 并不意味着所有的东西都转移到正确的地方,而是有其他一些含义(我可以想到一些含义,我需要更多的从个人提问)。 一个问题… 0011和0010怎么样。行sorting可能意味着你正在实现的algorithm已经被使用。 他的答案中指定的algorithm无法区分这两者。 我将两个答案的索引存储在一个数组中。 如果数组长度是1,那么你有一个解决scheme,否则你需要进一步递减…只是一个想法。 如果有人阅读这篇文章,可以在其他人的post上发表评论,请在评论中提及这篇文章。 这是一个严重的问题,如果有一个技术上不正确的答案得到检查会很不高兴。 如果我的评论被添加,我会完全删除我的答案。

最小的数字可以是0(看起来像(0000 … 0000)或1看起来像(0000 … 0001)。

每个更大的数字看起来像(xxxx … xx11)。 所以你应该检查每一行的最后一位数字。 如果它是0,那么检查最后一位数字是否为0.如果它是最小的数字。 如果不是,那么记住行号,并继续寻找最后一位数字为0的行。 如果你find它,这将是最小的数字。 如果不是,第一个find的数字是最小的一个。

这是N + 1步(最坏情况)的解决scheme,这是O(N)复杂度。

我不知道它是否被承认,但如果它被sorting,你不需要只是将每一行转换为十进制数,并select较低的一行。 例:

 [0111] -> 7 [0011] -> 3 [0000] -> 0 [0001] -> 1 

解决scheme是值为0的行。

我写了一个O(n)algorithm,类似于上面所说的,我们从左上angular开始向下进行:

 a = [ [0, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 1, 1] ] a2 = [ [0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 0, 1], [1, 1, 1, 1] ] def search(a): n = len(a) c = 0 r = 0 best_row = 0 while c<n and r<n: if a[r][c] == 0: c += 1 else: best_row = r r += 1 if c==n : best_row = r print( " best row: %d" % best_row ) search( a ) search( a2 )