【问题标题】:Number of 0's in a sorted boolean n*n matrix in log(n) timelog(n) 时间内排序布尔 n*n 矩阵中 0 的数量
【发布时间】:2016-07-02 08:43:49
【问题描述】:

这是一个谷歌面试问题。

给定一个包含 N 行 N 列的矩阵。矩阵中的元素可以是 1 或 0。矩阵的每一行和每一列都按升序排序。求给定矩阵中 0-s 的个数。

我想出了一个 O(n) 的解决方案,但根本无法提供一个 O(logn) 的解决方案。任何指针都非常感谢。

编辑:似乎 O(logn) 似乎不可能,如下所述。

【问题讨论】:

  • 展示你的 O(n) 解决方案
  • 你确定这在最坏情况复杂度 O(log n) 中实际上是可行的吗?可能是你忘记了问题的一些假设吗?或者,也许您在谈论平均案例复杂度
  • 向我们展示您的代码...我认为这是不可能的
  • 这是一个 O(n) 的解决方案:假设索引从 1 到 n,从 i=n 开始,j=1 做:如果元素是 1 那么 i--,如果是0 然后 j++。通过这种方式,您可以识别所有“枢轴”,即每行中的第一个 1(每当您从水平移动变为垂直移动时,您都会得到一个枢轴)。这最多需要 2n 步。
  • @Saphrosit 抱歉,但我不明白您的算法...请发布您的代码或示例或其他内容的链接...对我来说这没有任何意义

标签: algorithm search matrix


【解决方案1】:

首先,这是一个在 O(n) 时间内计算零的算法:

countZeroes(matrix):
    n = matrix.rowCount
    i = 0
    j = n-1
    count = 0
    while i < n && j >=0:
        if matrix[i][j] == 1 then:
            j--
        else:
            i++
            count += j+1
    return count

随着每次迭代增加 i 或减少 j,并且两者都只能在循环前取 0..n-1 之间的值结束,最大迭代次数为2n,即O(n)

这是一个 JavaScript sn-p,它生成一个 5x5 随机矩阵并使用上述算法计算零:

    function countZeroes(matrix) {
        var n = matrix.length,
            i = 0,
            j = n-1,
            count = 0;
        while (i < n && j >=0) {
            if (matrix[i][j] === 1) {
                j--;
            } else {
                i++;
                count += j+1;
            }
        }
        return count;
    }

    function randomMatrix(n) {
        var matrix = [],
            zeroCounts = [];
        for (var i = 0; i < n; i++) {
            zeroCounts[i] = Math.floor(Math.random() * (n+1));
        }
        zeroCounts.sort((a,b) => b-a); // descending
        for (var i = 0; i < n; i++) {
            matrix[i] = [];
            for (var j = 0; j < n; j++) {
                matrix[i][j] = j < zeroCounts[i] ? 0 : 1;
            }
        }
        return matrix;
    }

    function matrixToString(matrix) {
        var s = '';
        for (var i = 0; i < matrix.length; i++) {
            s += matrix[i].join('') + '\n';
        }
        return s;
    }

    var matrix = randomMatrix(5);
    console.log(matrixToString(matrix));
    console.log('Zeroes: ', countZeroes(matrix));

可以在O(log n)内完成吗?

想象一个这样的矩阵:

0000
0001
0011
0111

您需要访问此矩阵中的每一行以了解其中有多少个零。想象一下,您将只访问 4 行中的 3 行:它可以是任意 3...对于零的总数仍然至少有三种可能的结果,除非您还访问第四个。

例如,如果您访问过第 0 行、第 1 行和第 3 行,您会知道:

0000
0001
****
0111

通过对行和列进行排序,可以扣除:

0000
0001
0**1
0111

但剩余的** 可能是000111。找出答案的唯一方法是实际查看该行中的至少一个值。

结论:小于O(n)是不可能的。

【讨论】:

    【解决方案2】:

    假设在算法的过程中我们已经学习了矩阵的形式如下:

    000?
    00?1
    0?11
    ?111
    

    我们无法学习任何 ?从任何其他 ? 的值来看,所以我们需要查看它们中的每一个。因此,一般问题的任何解决方案至少需要 O(n) 时间,并且需要 log(n) 或 log²(n ) 时间是不可能的。

    【讨论】:

    • 这是真的,但这不是你学习事物的方式。假设 M(2,2) = 0 那么你知道 M(0..2,0..2) = 0。假设 M(2,2) = 0 和 M(3,2) = 1 然后你知道M(0..2,0..2) = 0 和 M(3..n,2..n) = 1
    • @LiorKogan 是的,这就是从 O(n^2) 到 O(n) 的改进的工作原理。上例中的?方块没有这样的顺序关系。
    【解决方案3】:

    使用二分法查找一行中的零个数可能会有所帮助!

    public static int findZerosV2(int[][] NxNMatrix) {
        int numZeros = 0;
        for (int i = 0; i < NxNMatrix.length; i++) {
            int numZerosInRow = binarySearch(NxNMatrix[i]);
            if (numZerosInRow > -1) {
                numZeros += numZerosInRow;
            }
        }
        return numZeros;
    }
    
    public static int binarySearch(int[] rowItem) {
        int foundZeros = -1;
        int rowIndex = 0;
        int highIndex = rowItem.length;
        for (int i = 0; i < rowItem.length; i++) {
            //find the middle element 
            int mIndex = (rowIndex + highIndex) / 2;
            if (rowItem[mIndex] == 0) {
                rowIndex = mIndex + 1;
                //keep count using index number of 0
                foundZeros = mIndex;
            } else
                highIndex = mIndex - 1;
        }
        //considering zero based index array
        return foundZeros + 1;
    }
    

    【讨论】:

      【解决方案4】:

      您可以对每一行使用二进制搜索来查找 0 变为 1 的位置。 Binarysearch 正在处理 O(log n) 中的排序数组。你会得到改变位置的索引号。您应该为每一行(n 次)执行此操作,然后时间将为 O(n* log n)

      【讨论】:

      • 顺便说一句:这里是二进制搜索的链接:en.wikipedia.org/wiki/Binary_search_algorithm
      • O(n*log n) 比 O(n) 差,O(n) 比 O(log n) 差,这是 OP 所要求的。此外,作者声称已经有一个 O(n) 算法
      • 我认为在 O(n) 中是不可能的,因为 O(n) 您需要遍历所有行,这也意味着 O(1) 就像找出从 0 开始的变化到 1 内一行是...这是不可能的...
      • 在对 OP 的评论中回答了
      【解决方案5】:

      对角线上的“中间”点二分查找,左上子矩阵全为0,右下子矩阵全为1。递归搜索左下和下- 右子矩阵?

      【讨论】:

      • “对每行的第一个(或最后一个取决于排序)元素使用二进制搜索”是什么意思?你的意思是对第一列进行二分搜索吗?如果是这种情况,那么您的解决方案不起作用。简单考虑只有第一行第一列为0的情况。
      猜你喜欢
      • 2012-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-19
      • 2015-07-06
      • 2017-05-15
      • 2011-07-09
      • 1970-01-01
      相关资源
      最近更新 更多