📜  OR值为1的子矩阵数

📅  最后修改于: 2021-05-06 20:46:06             🧑  作者: Mango

给定一个N * N二进制矩阵,任务是查找OR值为1的矩形子矩阵的计数。

例子:

Input : arr[][] = {{0, 0, 0},
                   {0, 0, 0},
                   {0, 0, 0}}
Output : 0
Explanation: All the submatrices will have an OR value 0.
Thus, ans = 0.

Input : arr[][] = {{0, 0, 0},
                  {0, 1, 0},
                  {0, 0, 0}}
Output : 16

一个简单的解决方案是生成所有可能的子矩阵,然后检查其中的任何值是否为1。如果对于子矩阵,至少单个元素为1,则将最终答案的值增加1。上述方法的时间复杂度为O(n 6 )。

更好的方法:让我们以另一种方式看待这个问题。现在,我们将尝试查找全为0的子矩阵的数量。对于最终答案,我们将从子矩阵总数中减去该值。

为了优化过程,对于矩阵的每个索引,我们将尝试查找从索引中所有值为0的子矩阵的数量。

解决这个问题的第一步是创建一个矩阵“ p_arr”。

  • 对于每个索引(R,C),如果arr [R] [C]等于0,则在p_arr [R] [C]中,我们将沿着行在单元格(R,C)的右侧存储0的数目在遇到“ 1”或数组末尾加1之前的“ R”。
  • 如果arr [R] [C]等于1,则p_arr [R] [C]等于零。

为了创建此矩阵,我们将使用以下递归关系。

IF arr[R][C] is 0
    p_arr[R][C] = p_arr[R][C+1] + 1
ELSE 
    p_arr[R][C] = 0

arr[][] = {{1, 0, 0, 0},
           {0, 1, 0, 1},
           {0, 1, 0, 0},
           {0, 0, 0, 0}}

p_arr[][] for above will look like
          {{0, 3, 2, 1},
           {1, 0, 1, 0},
           {1, 0, 2, 1},
           {4, 3, 2, 1}}

一旦有了所需的矩阵p_arr ,我们将开始按列处理矩阵’p_arr’。如果我们正在处理矩阵“ p_arr”的j列,那么对于该列的每个元素“ i”,我们将尝试查找从单元格(i,j)开始的全为0的子矩阵的数量。

为此,我们可以使用堆栈数据结构。

算法

  1. 初始化堆栈“ q”以存储被压入的元素的值以及堆栈中被压入的元素数的count(C ij ),其值严格大于当前元素的值。我们将使用对将两个数据捆绑在一起。
    将变量to_sum初始化为0。在每个步骤中,都将更新此变量以存储从在该步骤中被压入元素开始为全0的子矩阵数。因此,使用“ to_sum”,我们在每一步将全为0的子矩阵的数目更新为计数。
  2. 对于列“ j”,在任何步骤“ i”,我们都准备将p_arr [i] [j]压入堆栈。令Q t代表堆栈的最顶部元素,而C t代表先前推入堆栈的元素数量,其值大于堆栈的最顶端元素。在将元素“ p_arr [i] [j]”压入堆栈之前,如果堆栈不为空或最上面的元素大于要压入的数目,请继续弹出堆栈的最上面的元素,同时更新为to_sum等于to_sum + =(C t +1)*(Q t – p_arr [i] [j]) 。令C i,j表示大于在此堆栈中先前推送的当前元素的元素数。我们还需要跟踪C i,j 。因此,弹出一个元素之前,我们更新C I,J为C I,J + = C与to_sum沿
  3. 我们将全零的子矩阵数更新为count_zero_submatrices + = to_sum。
  4. 最后,将其与C i,j配对后,将其推入堆栈。

N * N矩阵中子矩阵的总数等于:

(N2 * (N + 1)2)/4

因此,最终答案将是:

ans = (N2 * (N + 1)2)/4 - count_zero_submatrices 

我们在O(N 2 )中创建前缀数组,对于每一列,我们将元素压入堆栈或仅弹出一次。因此,该算法的时间复杂度为O(N 2 )。

下面是上述方法的实现:

C++
// C++ program to count number of submatrices
// with OR value 1
  
#include 
#include 
#define n 3
using namespace std;
  
// Function to find required prefix-count for each row
// from right to left
void findPrefixCount(int p_arr[][n], bool arr[][n])
{
    for (int i = 0; i < n; i++)
        for (int j = n - 1; j >= 0; j--) {
  
            if (arr[i][j])
                continue;
            if (j != n - 1)
                p_arr[i][j] += p_arr[i][j + 1];
  
            p_arr[i][j] += (int)(!arr[i][j]);
        }
}
  
// Function to find the count of submatrices
// with OR value 1
int matrixOrValueOne(bool arr[][n])
{
    // Array to store prefix count of zeros from
    // right to left for boolean array
    int p_arr[n][n] = { 0 };
  
    findPrefixCount(p_arr, arr);
  
    // Variable to store the count of
    // submatrices with OR value 0
    int count_zero_submatrices = 0;
  
    // Loop to evaluate each column of
    // the prefix matrix uniquely.
    // For each index of a column we will try to
    // determine the number of sub-matrices
    // starting from that index
    // and has all 1s
    for (int j = 0; j < n; j++) {
  
        int i = n - 1;
  
        // stack to store elements and the count
        // of the numbers they popped
  
        // First part of pair will be the
        // value of inserted element.
        // Second part will be the count
        // of the number of elements pushed
        // before with a greater value
        stack > q;
  
        // Variable to store the number of submatrices
        // with all 0s
        int to_sum = 0;
  
        while (i >= 0) {
  
            int c = 0;
  
            while (q.size() != 0 and q.top().first > p_arr[i][j]) {
  
                to_sum -= (q.top().second + 1) * 
                             (q.top().first - p_arr[i][j]);
  
                c += q.top().second + 1;
  
                q.pop();
            }
  
            to_sum += p_arr[i][j];
  
            count_zero_submatrices += to_sum;
  
            q.push({ p_arr[i][j], c });
  
            i--;
        }
    }
  
    // Return the final answer
    return (n * (n + 1) * n * (n + 1)) / 4
           - count_zero_submatrices;
}
  
// Driver Code
int main()
{
    bool arr[][n] = { { 0, 0, 0 },
                      { 0, 1, 0 },
                      { 0, 0, 0 } };
  
    cout << matrixOrValueOne(arr);
  
    return 0;
}


Java
// Java program to count number of submatrices
// with OR value 1
import java.util.*;
  
class GFG
{
static int n = 3;
static class pair
{ 
    int first, second; 
    public pair(int first, int second) 
    { 
        this.first = first; 
        this.second = second; 
    } 
} 
  
// Function to find required prefix-count 
// for each row from right to left
static void findPrefixCount(int p_arr[][],
                            boolean arr[][])
{
    for (int i = 0; i < n; i++)
        for (int j = n - 1; j >= 0; j--)
        {
            if (arr[i][j])
                continue;
            if (j != n - 1)
                p_arr[i][j] += p_arr[i][j + 1];
  
            p_arr[i][j] += (arr[i][j] == false ? 1 : 0);
        }
}
  
// Function to find the count of submatrices
// with OR value 1
static int matrixOrValueOne(boolean arr[][])
{
    // Array to store prefix count of zeros from
    // right to left for boolean array
    int [][]p_arr = new int[n][n];
  
    findPrefixCount(p_arr, arr);
  
    // Variable to store the count of
    // submatrices with OR value 0
    int count_zero_submatrices = 0;
  
    // Loop to evaluate each column of
    // the prefix matrix uniquely.
    // For each index of a column we will try to
    // determine the number of sub-matrices
    // starting from that index
    // and has all 1s
    for (int j = 0; j < n; j++)
    {
        int i = n - 1;
  
        // stack to store elements and the count
        // of the numbers they popped
  
        // First part of pair will be the
        // value of inserted element.
        // Second part will be the count
        // of the number of elements pushed
        // before with a greater value
        Stack q = new Stack();
  
        // Variable to store the number of submatrices
        // with all 0s
        int to_sum = 0;
  
        while (i >= 0)
        {
            int c = 0;
  
            while (q.size() != 0 && 
                   q.peek().first > p_arr[i][j]) 
            {
  
                to_sum -= (q.peek().second + 1) * 
                          (q.peek().first - p_arr[i][j]);
  
                c += q.peek().second + 1;
  
                q.pop();
            }
  
            to_sum += p_arr[i][j];
  
            count_zero_submatrices += to_sum;
  
            q.add(new pair(p_arr[i][j], c ));
  
            i--;
        }
    }
  
    // Return the final answer
    return (n * (n + 1) * n * (n + 1)) / 4
        - count_zero_submatrices;
}
  
// Driver Code
public static void main(String[] args) 
{
    boolean arr[][] = { { false, false, false },
                        { false, true, false },
                        { false, false, false } };
  
    System.out.println(matrixOrValueOne(arr));
}
}
  
// This code is contributed by PrinciRaj1992


Python3
# Python3 program to count number 
# of submatrices with OR value 1 
  
# Function to find required prefix-count 
# for each row from right to left 
def findPrefixCount(p_arr, arr): 
  
    for i in range(0, n):
        for j in range(n - 1, -1, -1): 
  
            if arr[i][j]: 
                continue
            if j != n - 1: 
                p_arr[i][j] += p_arr[i][j + 1] 
  
            p_arr[i][j] += int(not arr[i][j]) 
  
# Function to find the count 
# of submatrices with OR value 1 
def matrixOrValueOne(arr): 
  
    # Array to store prefix count of zeros 
    # from right to left for boolean array 
    p_arr = [[0 for i in range(n)]      
                for j in range(n)] 
  
    findPrefixCount(p_arr, arr) 
  
    # Variable to store the count of 
    # submatrices with OR value 0 
    count_zero_submatrices = 0
  
    # Loop to evaluate each column of 
    # the prefix matrix uniquely. 
    # For each index of a column we will try 
    # to determine the number of sub-matrices 
    # starting from that index and has all 1s 
    for j in range(0, n): 
  
        i = n - 1
          
        # stack to store elements and the 
        # count of the numbers they popped 
  
        # First part of pair will be the 
        # value of inserted element. 
        # Second part will be the count 
        # of the number of elements pushed 
        # before with a greater value 
        q = [] 
  
        # Variable to store the number 
        # of submatrices with all 0s 
        to_sum = 0
          
        while i >= 0: 
  
            c = 0
            while (len(q) != 0 and 
                   q[-1][0] > p_arr[i][j]): 
  
                to_sum -= ((q[-1][1] + 1) * 
                           (q[-1][0] - p_arr[i][j]))
  
                c += q.pop()[1] + 1
  
            to_sum += p_arr[i][j] 
            count_zero_submatrices += to_sum 
  
            q.append((p_arr[i][j], c)) 
            i -= 1
  
    # Return the final answer 
    return ((n * (n + 1) * n * (n + 1)) // 
             4 - count_zero_submatrices) 
  
# Driver Code 
if __name__ == "__main__": 
  
    n = 3
    arr = [[0, 0, 0], 
           [0, 1, 0], 
           [0, 0, 0]] 
  
    print(matrixOrValueOne(arr))
  
# This code is contributed by Rituraj Jain


C#
// C# program to count number of submatrices
// with OR value 1
using System;
using System.Collections.Generic;
  
class GFG
{
static int n = 3;
class pair
{ 
    public int first, second; 
    public pair(int first, int second) 
    { 
        this.first = first; 
        this.second = second; 
    } 
} 
  
// Function to find required prefix-count 
// for each row from right to left
static void findPrefixCount(int [,]p_arr,
                            bool [,]arr)
{
    for (int i = 0; i < n; i++)
        for (int j = n - 1; j >= 0; j--)
        {
            if (arr[i, j])
                continue;
            if (j != n - 1)
                p_arr[i, j] += p_arr[i, j + 1];
  
            p_arr[i, j] += (arr[i, j] == false ? 1 : 0);
        }
}
  
// Function to find the count of submatrices
// with OR value 1
static int matrixOrValueOne(bool [,]arr)
{
    // Array to store prefix count of zeros from
    // right to left for bool array
    int [,]p_arr = new int[n, n];
  
    findPrefixCount(p_arr, arr);
  
    // Variable to store the count of
    // submatrices with OR value 0
    int count_zero_submatrices = 0;
  
    // Loop to evaluate each column of
    // the prefix matrix uniquely.
    // For each index of a column we will try to
    // determine the number of sub-matrices
    // starting from that index
    // and has all 1s
    for (int j = 0; j < n; j++)
    {
        int i = n - 1;
  
        // stack to store elements and the count
        // of the numbers they.Popped
  
        // First part of pair will be the
        // value of inserted element.
        // Second part will be the count
        // of the number of elements.Pushed
        // before with a greater value
        Stack q = new Stack();
  
        // Variable to store the number of 
        // submatrices with all 0s
        int to_sum = 0;
  
        while (i >= 0)
        {
            int c = 0;
  
            while (q.Count != 0 && 
                   q.Peek().first > p_arr[i, j]) 
            {
  
                to_sum -= (q.Peek().second + 1) * 
                          (q.Peek().first - p_arr[i, j]);
  
                c += q.Peek().second + 1;
  
                q.Pop();
            }
  
            to_sum += p_arr[i, j];
  
            count_zero_submatrices += to_sum;
  
            q.Push(new pair(p_arr[i, j], c));
  
            i--;
        }
    }
  
    // Return the final answer
    return (n * (n + 1) * n * (n + 1)) / 4 - 
                     count_zero_submatrices;
}
  
// Driver Code
public static void Main(String[] args) 
{
    bool [,]arr = { { false, false, false },
                    { false, true, false },
                    { false, false, false } };
  
    Console.WriteLine(matrixOrValueOne(arr));
}
}
  
// This code is contributed by Rajput-Ji


输出:
16