Largest row-wise and column-wise sorted sub-matrix - GeeksforGeeks

27 Jan, 2022
Given an N * M matrix mat[][], the task is to find the area-wise largest rectangular sub-matrix such that each column and each row of the sub-matrix is strictly increasing. 
Examples:  
Input: mat[][] = {{1, 2, 3}, {4, 5, 6}, {1, 2, 3}} Output: 6 Largest sub-matrix will be {{1, 2, 3}, {4, 5, 6}}. Number of elements in this sub-matrix = 6.
Input: mat[][] = {{1, 2, 3}, {4, 5, 3}, {1, 2, 3}} Output: 4 The largest sub-matrix will be {{1, 2}, {4, 5}} 
Approach: There are many approaches to solve this problem varying from O(N3 * M3) to O(N * M). In this article, an approach with O(N * M) time complexity using a stack will be discussed. Before proceeding further, its recommended to solve this. problem.
Let’s try to understand the approach broadly, then the algorithm will be discussed. For every column of the matrix, try to find the largest row-wise and column-wise sorted sub-matrix having the left edge at this column. To perform the same, create a matrix pre[][] where pre[i][j] will store the length of the longest increasing sub-array starting from the index j of the array arr[i].Now using this matrix, for each column j, find the length of the longest row-wise and column-wise sorted array. To process a column, all the increasing sub-segments of the array pre[][j] will be required. The same can be found using the two-pointer technique. In each of these sub-segments, simply find the largest area under the histogram considering the row-wise increasing sub-segments as bars. 
Create a prefix-sum array for each row ‘i’, which stores length of the largest increasing sub-array ending at each column ‘j’ of that row.
Once we have this array, for each column ‘j’. Initialize ‘i’ equals 0.Run a loop on ‘i’ while ‘i’ is less than ‘N’ Initialize ‘k’ equals i+1.while k less than N and arr[k][j] greater than arr[k-1][j], increment k.Apply histogram problem on the sub-array pre[i][j] to pre[k-1][j], to find the largest area under it. Let us call this value ‘V’. Update final answer as ans = max(ans, val).Update ‘i’ equals k-1.
Initialize ‘i’ equals 0.
Run a loop on ‘i’ while ‘i’ is less than ‘N’ Initialize ‘k’ equals i+1.while k less than N and arr[k][j] greater than arr[k-1][j], increment k.Apply histogram problem on the sub-array pre[i][j] to pre[k-1][j], to find the largest area under it. Let us call this value ‘V’. Update final answer as ans = max(ans, val).Update ‘i’ equals k-1.
Initialize ‘k’ equals i+1.
while k less than N and arr[k][j] greater than arr[k-1][j], increment k.
Apply histogram problem on the sub-array pre[i][j] to pre[k-1][j], to find the largest area under it. Let us call this value ‘V’. Update final answer as ans = max(ans, val).
Update ‘i’ equals k-1.
Below is the implementation of the above approach:  
C++
Java
Python3
C#
Javascript
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std; // Function to return the largest// area under a histogramint histo(vector<int> q){     // Stack    stack<int> q1;     // Length of the vector    int n = q.size();     // Function to store the next smaller    // and previous smaller index    int pre_smaller[q.size()];    int next_smaller[q.size()];     // Finding the next smaller    for (int i = 0; i < n; i++)        pre_smaller[i] = -1, next_smaller[i] = n;    for (int i = 0; i < n; i++) {        while (q1.size() and q[q1.top()] > q[i]) {            next_smaller[q1.top()] = i;            q1.pop();        }        q1.push(i);    }     // Finding the previous smaller element    while (q1.size())        q1.pop();    for (int i = n - 1; i >= 0; i--) {        while (q1.size() and q[q1.top()] > q[i]) {            pre_smaller[q1.top()] = i;            q1.pop();        }        q1.push(i);    }     // To store the final answer    int ans = 0;     // Finding the final answer    for (int i = 0; i < n; i++)        ans = max(ans, (next_smaller[i]                        - pre_smaller[i] - 1)                           * q[i]);     // Returning the final answer    return ans;} // Function to return the largest area// for the required submatrixint findLargest(vector<vector<int> > arr){    // n and m store the number of    // rows and columns respectively    int n = arr.size();    int m = arr[0].size();     // To store the prefix_sum    int pre[n][m];     // To store the final answer    int ans = 0;     // Loop to create the prefix-sum    // using two pointers    for (int i = 0; i < n; i++)        for (int j = 0; j < m; j++) {            if (j == 0) {                pre[i][j] = 1;                continue;            }            if (arr[i][j] > arr[i][j - 1])                pre[i][j] = pre[i][j - 1] + 1;            else                pre[i][j] = 1;        }     // For each column run the loop    for (int j = 0; j < m; j++) {         // Find the largest row-wise sorted arrays        for (int i = 0; i < n; i++) {            int k = i + 1;            vector<int> q;            q.push_back(pre[i][j]);            while (k < n and arr[k] > arr[k - 1])                q.push_back(pre[k][j]), k++;             // Applying the largest area            // under the histogram            ans = max(ans, histo(q));            i = k - 1;        }    }     // Return the final answer    return ans;} // Driver codeint main(){    vector<vector<int> > arr = { { 1, 2, 3 },                                 { 4, 5, 6 },                                 { 1, 2, 3 } };     cout << findLargest(arr);     return 0;}
// Java implementation of the approachimport java.io.*;import java.util.*;class GFG{   // Function to return the largest  // area under a histogram  static int histo(ArrayList<Integer> q)  {     // Stack    Stack<Integer> q1 = new Stack<Integer>();     // Length of the vector    int n = q.size();     // Function to store the next smaller    // and previous smaller index    int[] pre_smaller = new int[q.size()];    int[] next_smaller = new int[q.size()];     // Finding the next smaller    for (int i = 0; i < n; i++)    {      pre_smaller[i] = -1;      next_smaller[i] = n;    }    for (int i = 0; i < n; i++)    {      while (q1.size() > 0 && q.get(q1.peek()) > q.get(i))      {        next_smaller[q1.peek()] = i;        q1.pop();      }      q1.push(i);    }     // Finding the previous smaller element    while (q1.size() > 0)    {      q1.pop();    }    for (int i = n - 1; i >= 0; i--)    {      while (q1.size() > 0 && q.get(q1.peek()) > q.get(i))      {        pre_smaller[q1.peek()] = i;        q1.pop();      }      q1.push(i);    }     // To store the final answer    int ans = 0;     // Finding the final answer    for (int i = 0; i < n; i++)    {      ans = Math.max(ans, (next_smaller[i] -                           pre_smaller[i] - 1) *                     q.get(i));     }     // Returning the final answer    return ans;  }   // Function to return the largest area  // for the required submatrix  static int findLargest(ArrayList<ArrayList<Integer>> arr)  {     // n and m store the number of    // rows and columns respectively    int n = arr.size();    int m = arr.get(0).size();     // To store the prefix_sum    int[][] pre=new int[n][m];     // To store the final answer    int ans = 0;     // Loop to create the prefix-sum    // using two pointers    for (int i = 0; i < n; i++)    {      for (int j = 0; j < m; j++)      {        if (j == 0)        {          pre[i][j] = 1;          continue;        }        if(arr.get(i).get(j) > arr.get(i).get(j - 1))        {          pre[i][j] = pre[i][j - 1] + 1;        }        else        {          pre[i][j] = 1;        }      }    }     // For each column run the loop    for (int j = 0; j < m; j++)    {       // Find the largest row-wise sorted arrays      for (int i = 0; i < n; i++)      {        int k = i + 1;        ArrayList<Integer> q = new ArrayList<Integer>();        q.add(pre[i][j]);        while (k < n && arr.get(k).get(0) > arr.get(k - 1).get(0))        {          q.add(pre[k][j]);          k++;        }         // Applying the largest area        // under the histogram        ans = Math.max(ans, histo(q));        i = k - 1;      }    }     // Return the final answer    return ans;  }   // Driver code  public static void main (String[] args)  {    ArrayList<ArrayList<Integer>> arr = new ArrayList<ArrayList<Integer>>();    arr.add(new ArrayList<Integer>(Arrays.asList(1, 2, 3 )));    arr.add(new ArrayList<Integer>(Arrays.asList(4, 5, 6 )));    arr.add(new ArrayList<Integer>(Arrays.asList(1, 2, 3 )));    System.out.println(findLargest(arr));  }} // This code is contributed by avanitrachhadiya2155
# Python3 implementation of the approach # Function to return the largest# area under a histogramdef histo(q):     # Stack    q1 = []     # Length of the vector    n = len(q)     # Function to store the next smaller    # and previous smaller index    pre_smaller = [0 for i in range(len(q))]    next_smaller = [0 for i in range(len(q))]     # Finding the next smaller    for i in range(n):        pre_smaller[i] = -1        next_smaller[i] = n    for i in range(n):        while (len(q1) > 0 and q[q1[-1]] > q[i]):            next_smaller[q1[-1]] = i            del q1[-1]        q1.append(i)      # Finding the previous smaller element    while (len(q1) > 0):        del q1[-1]     for i in range(n - 1, -1, -1):        while (len(q1) > 0 and q[q1[-1]] > q[i]):            pre_smaller[q1[-1]] = i            del q1[-1]         q1.append(i)     # To store the final answer    ans = 0     # Finding the final answer    for i in range(n):        ans = max(ans, (next_smaller[i]- pre_smaller[i] - 1)* q[i])     # Returning the final answer    return ans # Function to return the largest area# for the required submatrixdef findLargest(arr):         # n and m store the number of    # rows and columns respectively    n = len(arr)    m = len(arr[0])     # To store the prefix_sum    pre = [[0 for i in range(m)] for i in range(n)]     # To store the final answer    ans = 0     # Loop to create the prefix-sum    # using two pointers    for i in range(n):        for j in range(m):            if (j == 0):                pre[i][j] = 1                continue             if (arr[i][j] > arr[i][j - 1]):                pre[i][j] = pre[i][j - 1] + 1            else:                pre[i][j] = 1      # For each column run the loop    for j in range(m):         # Find the largest row-wise sorted arrays        for i in range(n):            k = i + 1            q = []            q.append(pre[i][j])            while (k < n and arr[k] > arr[k - 1]):                q.append(pre[k][j])                k += 1             # Applying the largest area            # under the histogram            ans = max(ans, histo(q))            i = k - 1     # Return the final answer    return ans # Driver code arr = [ [ 1, 2, 3 ],    [ 4, 5, 6 ],    [ 1, 2, 3 ] ] print(findLargest(arr)) # This code is contributed by mohit kumar 29
// C# implementation of the approachusing System;using System.Collections.Generic; class GFG{     // Function to return the largest// area under a histogramstatic int histo(List<int> q){         // Stack    Stack<int> q1 = new Stack<int>();         // Length of the vector    int n = q.Count;         // Function to store the next smaller    // and previous smaller index    int[] pre_smaller = new int[q.Count];    int[] next_smaller = new int[q.Count];         // Finding the next smaller    for(int i = 0; i < n; i++)    {        pre_smaller[i] = -1;        next_smaller[i] = n;    }    for(int i = 0; i < n; i++)    {        while (q1.Count > 0 && q[q1.Peek()] > q[i])        {            next_smaller[q1.Peek()] = i;            q1.Pop();        }        q1.Push(i);    }         // Finding the previous smaller element    while (q1.Count > 0)    {        q1.Pop();    }         for(int i = n - 1; i >= 0; i--)    {        while (q1.Count > 0 && q[q1.Peek()] > q[i])        {            pre_smaller[q1.Peek()] = i;            q1.Pop();        }        q1.Push(i);    }         // To store the final answer    int ans = 0;         // Finding the final answer    for(int i = 0; i < n; i++)    {        ans = Math.Max(ans, (next_smaller[i] -                              pre_smaller[i] - 1) * q[i]);    }         // Returning the    // final answer    return ans;} // Function to return the largest area// for the required submatrixstatic int findLargest(List<List<int>> arr){         // n and m store the number of    // rows and columns respectively    int n = arr.Count;    int m = arr[0].Count;         // To store the prefix_sum    int[,] pre = new int[n, m];         // To store the final answer    int ans = 0;         // Loop to create the prefix-sum    // using two pointers    for(int i = 0; i < n; i++)    {        for(int j = 0; j < m; j++)        {            if (j == 0)            {                pre[i, j] = 1;                continue;            }                         if (arr[i][j] > arr[i][j - 1])            {                pre[i, j] = pre[i,j - 1] + 1;            }            else            {                pre[i, j] = 1;            }        }    }         // For each column run the loop    for(int j = 0; j < m; j++)    {                 // Find the largest row-wise sorted arrays        for(int i = 0; i < n; i++)        {            int k = i + 1;            List<int> q = new List<int>();            q.Add(pre[i, j]);                         while(k < n && arr[k][0] > arr[k - 1][0])            {                q.Add(pre[k, j]);                k++;            }                         // Applying the largest area            // under the histogram            ans = Math.Max(ans, histo(q));            i = k - 1;        }    }         // Return the final answer    return ans;} // Driver codestatic public void Main(){    List<List<int>> arr = new List<List<int>>();    arr.Add(new List<int>(){1, 2, 3});    arr.Add(new List<int>(){4, 5, 6 });    arr.Add(new List<int>(){1, 2, 3});         Console.WriteLine(findLargest(arr));}} // This code is contributed by rag2127
<script>// Javascript implementation of the approach // Function to return the largest  // area under a histogramfunction histo(q){    // Stack    let q1 = [];      // Length of the vector    let n = q.length;      // Function to store the next smaller    // and previous smaller index    let pre_smaller = new Array(q.length);    let next_smaller = new Array(q.length);      // Finding the next smaller    for (let i = 0; i < n; i++)    {      pre_smaller[i] = -1;      next_smaller[i] = n;    }    for (let i = 0; i < n; i++)    {      while (q1.length > 0 && q[q1[q1.length-1]] > q[i])      {        next_smaller[q1[q1.length-1]] = i;        q1.pop();      }      q1.push(i);    }      // Finding the previous smaller element    while (q1.length > 0)    {      q1.pop();    }    for (let i = n - 1; i >= 0; i--)    {      while (q1.length > 0 && q[q1[q1.length-1]] > q[i])      {        pre_smaller[q1[q1.length-1]] = i;        q1.pop();      }      q1.push(i);    }      // To store the final answer    let ans = 0;      // Finding the final answer    for (let i = 0; i < n; i++)    {      ans = Math.max(ans, (next_smaller[i] -                           pre_smaller[i] - 1) *                     q[i]);      }      // Returning the final answer    return ans;} // Function to return the largest area  // for the required submatrixfunction findLargest(arr){    // n and m store the number of    // rows and columns respectively    let n = arr.length;       let m = arr[0].length;      // To store the prefix_sum    let pre=new Array(n);    for(let i=0;i<n;i++)    {        pre[i]=new Array(m);        for(let j=0;j<m;j++)        {            pre[i][j]=0;        }    }      // To store the final answer    let ans = 0;      // Loop to create the prefix-sum    // using two pointers    for (let i = 0; i < n; i++)    {      for (let j = 0; j < m; j++)      {        if (j == 0)        {          pre[i][j] = 1;          continue;        }        if(arr[i][j] > arr[i][j - 1])        {          pre[i][j] = pre[i][j - 1] + 1;        }        else        {          pre[i][j] = 1;        }      }    }      // For each column run the loop    for (let j = 0; j < m; j++)    {        // Find the largest row-wise sorted arrays      for (let i = 0; i < n; i++)      {        let k = i + 1;        let q = [];        q.push(pre[i][j]);        while (k < n && arr[k][0] > arr[k - 1][0])        {          q.push(pre[k][j]);          k++;        }          // Applying the largest area        // under the histogram        ans = Math.max(ans, histo(q));        i = k - 1;      }    }      // Return the final answer    return ans;}  // Driver codelet arr=[[1, 2, 3],[4, 5, 6 ],[1, 2, 3]];document.write(findLargest(arr)); // This code is contributed by patel2127</script>
6
 
Time Complexity: O(N2)Auxiliary Space: O(N2). 
mohit kumar 29
avanitrachhadiya2155
rag2127
khushboogoyal499
patel2127
gabaa406
pankajsharmagfg
surinderdawra388
media.net
submatrix
Data Structures
Matrix
Stack
Data Structures
Stack
Matrix
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Introduction to Tree Data Structure
TCS NQT Coding Sheet
Program to implement Singly Linked List in C++ using class
Hash Functions and list/types of Hash functions
Static Data Structure vs Dynamic Data Structure
Matrix Chain Multiplication | DP-8
Program to find largest element in an array
Print a given matrix in spiral form
Sudoku | Backtracking-7
Rat in a Maze | Backtracking-2