【问题标题】:In a square matrix, where each cell is black or white. Design an algorithm to find the max sub-square such that all 4 borders are black在方阵中,每个单元格都是黑色或白色。设计一个算法来找到最大的子正方形,使得所有 4 个边框都是黑色的
【发布时间】:2011-12-27 04:43:51
【问题描述】:

给定一个方阵,其中每个单元格是黑色或白色。设计一个算法来找到最大的子正方形,使得所有 4 个边框都是黑色的。

我有 O(n^2) 算法:

从左到右扫描每一列,对于每一列中的每个单元格,扫描每一行以找到带有后边框的最大子正方形。

有更好的解决方案吗?

谢谢

【问题讨论】:

  • 疯狂的想法:如果您的矩阵很大,也许具有良好选择的动量空间基础的离散傅里叶变换可以很好地估计结果方阵的 大小 .不过,不知道这是否实用。
  • 对于每个单元格做的线性工作量对我来说听起来像 O(n^3)。
  • 我们可以看看你的 0(n^2) 算法吗? :) 我在 discuss.techinterview.org/default.asp?interview.11.445656.19 看到了一个讨论,每个人都被困在 0(n^3)。
  • 如果您以这种方式扫描,您实际上不必再次扫描您在之前扫描中遇到的单元格,对吗?
  • 子方块的“边界”是它的外层,还是周围的层?例如,对于子方格 (5,5)-(10,10),是 (5,5) 到 (5,10) 到 (10,10) 到 (10,5) 到 (5,5) 还是(4,4) 到 (4,11) 到 (11,11) 到 (11,4) 到 (4,4) ?

标签: c++ c performance algorithm data-structures


【解决方案1】:

O(n^2) 是可能的。我想这是最优的,因为你有 n^2 个单元格。

注意任何正方形的左上角和右下角都在同一条对角线上。

现在,如果我们可以在 O(n) 时间内处理每个对角线,我们将有一个 O(n^2) 时间的算法。

假设我们有一个左上角的候选人。我们可以计算它下面和右边的连续黑色单元的数量,取两者中的最小值,称之为T。

对于右下角的候选者,我们可以计算它左边的连续黑色单元格的数量,然后到顶部并取两者中的最小值,称为 B。

一旦我们有了 T 和 B 这两个数字,我们就可以判断给定的左上角、右下角候选者是否真的给了我们一个全黑边框的正方形。

现在可以在 O(n^2) 时间内计算每个单元格的这两个数字,方法是四次遍历整个矩阵(如何?)。

所以让我们假设已经完成。

现在考虑对角线。我们的目标是在 O(n) 时间内沿着这条对角线找到一个左上右下的对。

假设我们在数组 T[1...m] 中计算了 T,其中 m 是对角线的长度。同样,我们有一个数组 B[1...m]。 T[1] 对应于对角线的左上端,T[m] 对应于右下角。与 B 类似。

现在我们如下处理对角线,对于每个左上角的候选 i,我们尝试找到一个右下角的候选 j,它将给出最大的正方形。注意 j >= i。另请注意,如果 (i,j) 是候选者,则 (i',j) 不是,其中 i' > i。

请注意,如果T[i] >= j-i+1 和B[j] >= j-i+1,则 i 和 j 形成一个正方形。

即T[i] +i - 1 >= j 和 B[j] -j - 1 >= -i。

所以我们形成了新的数组,例如 TL[k] = T[k] + k -1 和 BR[k] = B[k] -k - 1。

因此,给定两个新数组 TL 和 BR,以及一个 i,我们需要回答以下问题:

满足 TL[i] >= j 和 BR[j] >= -i 的最大 j 是多少?

现在假设我们能够处理范围最大查询的 BR(可以在 O(m) 时间内完成)。

现在给定 TL[i],在 [i, TL[i]] 范围内,我们找到 BR 的最大值,比如 BR[j1]。

现在如果 BR[j1] >= -i,我们在 [j1, TL[i]] 范围内找到 BR 的最大值,然后继续这种方式。

一旦我们找到 (TL[i],BR[j]) 候选,我们就可以忽略未来 i 的数组 BR[1...j]。

这允许我们在 O(n) 时间内处理每个对角线,从而给出一个 O(n^2) 总算法。

我省略了很多细节并给出了草图,因为它已经太长了。随意编辑此说明。

呼。

【讨论】:

    【解决方案2】:

    C++ 代码:

    #include<iostream>
    using namespace std;
    
    int min(int a,int b,int c)
    {
        int min = a;
        if(min > b)
            min = b;
        if(min > c)
            min = c;
        return min;
    }
    
    int main()
    {
        const int size  = 5;
        char a[size][size] = { {'b','b','b','b','w'},{'b','b','b','b','b'},{'b','b','b','b','b'},{'b','b','w','b','b'},{'b','w','w','b','b'} };
        int arr[size+1][size+1];
        // First row and First column of arr is zero.
        for(int i=0;i<size+1;i++)
        {
            arr[0][i] = 0;
            arr[i][0] = 0;
        }
        int answer = 0;
        for(int i=0;i<size;i++)
        {
            for(int j=0;j<size;j++)
            {
                if(a[i][j] == 'w')
                    arr[i+1][j+1] = 0;
                if(a[i][j] == 'b')
                {
                    int minimum = min(arr[i][i],arr[i+1][j],arr[i][j+1]);
                    arr[i+1][j+1] = minimum + 1;
                    if( arr[i+1][j+1] > answer)
                        answer = arr[i+1][j+1];
                }
            }
        }
        for(int i=0;i<size+1;i++)
        {
            for(int j=0;j<size+1;j++)
            {
                cout<<arr[i][j]<<"\t";
            }
            cout<<endl;
        }
        cout<<answer<<endl;
        return 0;
    }
    

    【讨论】:

    • 我认为你的代码解决了一个不同的问题。您的代码没有找到所有黑色方块中最大的子方块吗?问题要求找到每个 border 方块都是黑色的最大子方块。
    【解决方案3】:
    /* In a square matrix, where each cell is black or white. 
     * Design an algorithm to find the max sub-square such that all 4 borders are black. The right Java implementation based on a previous post. 
     */
    public int maxSubsquare(boolean[][] M){
        int n = M.length; 
        maxsize=0; 
        checkDiag(M, 0, 0, n); 
        for (int i=1; i<n; i++){
            checkDiag(M, i, 0, n); 
            checkDiag(M, 0, i, n); 
        }
        return maxsize; 
    }
    int maxsize; 
    void checkDiag(boolean[][] M, int i, int j, int n){
        if (i>=n-maxsize || j>=n-maxsize) return; 
        int step = 0; 
        while (step<(n-Math.max(i, j))&& M[i][j+step]&&M[i+step][j]){
            int s = step; 
            while (s>0){
                if (M[i+s][j+step]&&M[i+step][j+s]) s--; 
                else break; 
            }
            if (s==0) 
                maxsize = Math.max(maxsize, step+1); 
            step++; 
        }
        if (step==0) checkDiag(M, i+step+1, j+step+1, n); 
        else checkDiag(M, i+step, j+step, n); 
    }
    

    【讨论】:

      【解决方案4】:

      我不知道为什么你可以得到一个 O(n^2) 算法。从数学上讲,这是不可能的。 假设您有一个 NxN 矩阵。您需要检查: 1. 1个矩阵大小:NxN, 2. 2*2 大小的矩阵:(N-1)x(N-1), 3. 3*3 大小的矩阵:(N-2)x(N-2), ....

      总共需要检查:1+ 2^2 + 3^2 + ... + N^2 = N(N+1)(2N+1)/6。 所以任何算法都不能比 O(N^3) 做得更好

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-30
        • 2020-07-01
        • 2013-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多