【问题标题】:Counting sub matrix with all prime numbers用所有素数计算子矩阵
【发布时间】:2018-10-05 08:30:45
【问题描述】:

我得到一个 NxN 矩阵。如果满足以下条件,则认为子矩阵是特殊的:

  1. 必须是正方形
  2. 所有数字都必须是素数。

我必须计算给定矩阵中满足以下条件的子矩阵的总数。

例如,让样本输入为=>

3
3 5 6
8 3 2
3 5 2

样本输出:8

解释:

  • 1x1:有 7 个素数,每个 1x1 矩阵包含 1 个素数
  • 2x2:只有右下子矩阵包含所有素数
  • 3x3:没有 3x3 矩阵满足这些条件

所以最后的答案是 (7+1+0)=8

我最近在一次采访中遇到了这个问题。我可以想出一个蛮力解决方案。解决这个问题的最佳方法是什么?

[更新] 我已经粘贴了解决问题的尝试。

class TestClass 
{
    public static boolean isPrime(int n)
    {
        if(n<2)
            return false;
        for(int i=2;i<=Math.sqrt(n);i++)
        {
            if(n%i==0)
                return false;
        }
        return true;
    }
    public static boolean scan_matrix(boolean a[][], int start_i, int start_j, int n)
    {
        for(int i=start_i;i<start_i+n;i++)
        {
            for(int j=start_j;j<start_j+n;j++)
            {
                if(!a[i][j])
                    return false;
            }
        }
        return true;
    }
    public static int count_valid_matrix(boolean a[][], int n, int N)
    {
        int result = 0;
        for(int start_i=0;start_i<=N-n;start_i++)
        {
            for(int start_j=0;start_j<=N-n;start_j++)
            {
                if(scan_matrix(a, start_i, start_j, n))
                    result += 1;
            }
        }
        return result;
    }

    public static void main(String args[]) throws Exception
    {
        Scanner s = new Scanner(System.in);
        int N = s.nextInt();
        boolean a[][] = new boolean[N][N];
        int result = 0;
        for(int i=0;i<N; i++)
        {
            for(int j=0;j<N;j++)
            {
                int num = s.nextInt();
                a[i][j] = isPrime(num);
                if(a[i][j])
                    result += 1;
            }
        }
        int n = 2;
        while(n<N)
        {
            result += count_valid_matrix(a, n, N);
            n++;
        }
        System.out.println(result);
    }
}

【问题讨论】:

  • 你能展示一下你的尝试吗?
  • 看起来很适合动态规划算法。 2x2 矩阵实际上是 4 个彼此相邻的 1x1 矩阵,这意味着从根本上说,如果您解决较小矩阵的问题并保存相关信息,它应该会建立起来。
  • 提示 1:每个 2x2 子矩阵包含四个 1x1 子矩阵。每个 3x3 子矩阵包含四个 2x2 子矩阵。提示 2:Sieve of Eratosthenes

标签: java algorithm matrix dynamic-programming


【解决方案1】:

这是一种可能的表述的一部分。让is_special(I, J, W) 表示矩阵单元m(I, J) 是否是宽度为W 的有效正方形的右下角。那么:

is_special(I, J, 1) ->
  is_prime( m(I, J) );

is_special(I, J, W) ->
  (I >= W - 1 andalso                     % assuming I starts from 0
    (J >= W - 1 andalso                   % assuming J starts from 0
      (is_special(I, J, W - 1) and
       is_special(I - 1, J, W - 1) and
       is_special(I, J - 1, W - 1) and
       is_special(I - 1, J - 1, W - 1)))).

【讨论】:

    【解决方案2】:

    想法

    首先,将您的矩阵转换(您所做的)为 0/1 矩阵, 0 用于非质数,1 用于质数。

    现在,您有一个“表面”1s。你能在这个表面上放多少个正方形? 想一想:如果你有一个1s 的3*3 平方,从(0,0) 开始,那么你已经 知道正方形(1,0)-(2,1)(0,1)-(1,2)(1,1)-(2,2) 是由1s 组成的,因此您不必再次检查这些正方形。 因此,您将从(1,0)(0,1)(1,1) 开始寻找1s 的正方形,只有当它们大于2*2。 想象一下从(1,0) 开始的最大正方形的大小为3*3,但另外两个是2*2。 您可以忽略后者(它们不会添加任何新内容),但您必须添加新的3*3 正方形并删除与前一个重叠的表面。

    这可以概括如下:

    • 将从(0,0) 开始的最大正方形存储在矩阵M
    • N = 大小为M[0,0] 的正方形中子正方形的数量
    • 对于每个(r,c),从左到右和从上到下:
      • M 获取最大的正方形大小,从(r-1,c)(r,c-1)(r-1,c-1) 开始,比如说K
        • 计算从(r,c) 开始的最大正方形大小(从K-1 开始)
        • 如果M[r,c] = K-1,什么也不做
        • 如果M[r,c] > K-1,更新N: N += 大小为M[r,c] 的正方形中子正方形的数量 - 的数量 大小为K-1 的正方形中的子正方形

    诀窍在于“计算从(r,c) 开始的最大正方形大小(从K-1 开始)”将省去大量比较。

    伪代码(类似 Python)

    首先,请注意大小为k 的正方形包含大小为k^2 的正方形1(k-1)^2 的正方形 大小2, ..., 1 大小为k 的正方形。这是一个众所周知的总和(我从维基百科获取结果!):

    subsquares_count(k) = 1/6*k + 1/2*k^2 + 1/3*k^3
    

    计算1s 盯着(r, c) 的最大正方形的大小并不难。我添加一个从K开始:

    def largest_square_size(m, r, c, K):
        k = K
        while k<n:
            # check the border
            for l in 0..k:
                if m[r+k, c+l] == 0 or m[r+l, c+k] == 0: # consider the left and bottom borders
                    break while
            if m[r+k, c+k] == 0 # don't forget the corner
                break while
            k += 1
        return k
    

    现在,主循环的草图:

    for r in 0..n:
        for c in 0..n: 
            K = max(M[r-1,c-1], M[r-1,c], M[r,c-1]) - 1 # add boundary check, K = 0 if r,c = 0,0
            M[r,c] = largest_square_size(m, r, c, K)
            if M[r,c] > K:
                N += subsquares_count(M[0,0]) - subsquares_count(K)
    

    免责声明:我没有对此进行测试,可能存在边缘情况,但我认为这是正确的。

    这显然不是最理想的,因为某些位置可能会被检查多次,但它应该表现良好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-30
      • 2015-05-17
      • 2021-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      相关资源
      最近更新 更多