给定一个二维矩阵mat[][]和一个值k 。找到总和等于k的最大矩形子矩阵。
例子:
Input : mat = { { 1, 7, -6, 5 },
{ -8, 6, 7, -2 },
{ 10, -15, 3, 2 },
{ -5, 2, 0, 9 } }
k = 7
Output : (Top, Left): (0, 1)
(Bottom, Right): (2, 3)
7 -6 5
6 7 -2
-15 3 2
天真的方法:检查给定二维数组中总和等于“k”的每个可能的矩形并打印最大的一个。该解决方案需要 4 个嵌套循环,并且该解决方案的时间复杂度为 O(n^4)。
有效的方法:可以使用一维数组和 k 的最长子数组将时间复杂度降低到 O(n^3)。这个想法是一一固定左列和右列,并为每个左列和右列对的连续行找到总和等于“k”的最长子数组。我们基本上找到每个固定的左右列对的顶部和底部行号(它们是最大子矩阵的一部分)。要找到顶部和底部的行号,从左到右计算每行元素的总和,并将这些总和存储在一个数组中,比如 temp[]。所以 temp[i] 表示第 i 行从左到右的元素总和。现在,在 temp[] 上应用具有和 k 一维算法的最长子数组,并获得总和等于 temp[] 的 ‘k’ 的最长子数组。此长度将是左和右作为边界列的最大可能长度。为左右列对设置“顶部”和“底部”行索引并计算面积。以类似的方式获取总和等于“k”的其他子矩阵的顶部、底部、左侧、右侧索引,并打印具有最大面积的那个。
C++
// C++ implementation to find the largest area rectangular
// sub-matrix whose sum is equal to k
#include
using namespace std;
const int MAX = 100;
// This function basically finds largest 'k'
// sum subarray in arr[0..n-1]. If 'k' sum
// doesn't exist, then it returns false. Else
// it returns true and sets starting and
// ending indexes as start and end.
bool sumEqualToK(int arr[], int& start,
int& end, int n, int k)
{
// unordered_map 'um' implemented
// as hash table
unordered_map um;
int sum = 0, maxLen = 0;
// traverse the given array
for (int i = 0; i < n; i++) {
// accumulate sum
sum += arr[i];
// when subarray starts from index '0'
// update maxLength and start and end points
if (sum == k) {
maxLen = i + 1;
start = 0;
end = i;
}
// make an entry for 'sum' if it is
// not present in 'um'
if (um.find(sum) == um.end())
um[sum] = i;
// check if 'sum-k' is present in 'um'
// or not
if (um.find(sum - k) != um.end()) {
// update maxLength and start and end points
if (maxLen < (i - um[sum - k])) {
maxLen = i - um[sum - k];
start = um[sum - k] + 1;
end = i;
}
}
}
// Return true if maximum length is non-zero
return (maxLen != 0);
}
// function to find the largest area rectangular
// sub-matrix whose sum is equal to k
void sumZeroMatrix(int mat[][MAX], int row, int col, int k)
{
// Variables to store the temporary values
int temp[row], area;
bool sum;
int up, down;
// Variables to store the final output
int fup = 0, fdown = 0, fleft = 0, fright = 0;
int maxArea = INT_MIN;
// Set the left column
for (int left = 0; left < col; left++) {
// Initialize all elements of temp as 0
memset(temp, 0, sizeof(temp));
// Set the right column for the left column
// set by outer loop
for (int right = left; right < col; right++) {
// Calculate sum between current left
// and right column for every row 'i'
for (int i = 0; i < row; i++)
temp[i] += mat[i][right];
// Find largest subarray with 'k' sum in
// temp[]. The sumEqualToK() function also
// sets values of 'up' and 'down;'. So
// if 'sum' is true then rectangle exists between
// (up, left) and (down, right) which are the
// boundary values.
sum = sumEqualToK(temp, up, down, row, k);
area = (down - up + 1) * (right - left + 1);
// Compare no. of elements with previous
// no. of elements in sub-Matrix.
// If new sub-matrix has more elements
// then update maxArea and final boundaries
// like fup, fdown, fleft, fright
if (sum && maxArea < area) {
fup = up;
fdown = down;
fleft = left;
fright = right;
maxArea = area;
}
}
}
// If there is no change in boundaries
// than check if mat[0][0] equals 'k'
// If it is not equal to 'k' then print
// that no such k-sum sub-matrix exists
if (fup == 0 && fdown == 0 && fleft == 0 &&
fright == 0 && mat[0][0] != k) {
cout << "No sub-matrix with sum " << k << " exists";
return;
}
// Print final values
cout << "(Top, Left): "
<< "(" << fup << ", " << fleft
<< ")" << endl;
cout << "(Bottom, Right): "
<< "(" << fdown << ", " << fright
<< ")" << endl;
for (int j = fup; j <= fdown; j++) {
for (int i = fleft; i <= fright; i++)
cout << mat[j][i] << " ";
cout << endl;
}
}
// Driver program to test above
int main()
{
int mat[][MAX] = { { 1, 7, -6, 5 },
{ -8, 6, 7, -2 },
{ 10, -15, 3, 2 },
{ -5, 2, 0, 9 } };
int row = 4, col = 4;
int k = 7;
sumZeroMatrix(mat, row, col, k);
return 0;
}
Java
// Java implementation to find
// the largest area rectangular
// sub-matrix whose sum is equal to k
import java.util.*;
class GFG
{
static int MAX = 100;
static int start, end;
// This function basically finds largest 'k'
// sum subarray in arr[0..n-1]. If 'k' sum
// doesn't exist, then it returns false. Else
// it returns true and sets starting and
// ending indexes as start and end.
static boolean sumEqualToK(int arr[], int n, int k)
{
// unordered_map 'um' implemented
// as hash table
HashMap um =
new HashMap();
int sum = 0, maxLen = 0;
// traverse the given array
for (int i = 0; i < n; i++)
{
// accumulate sum
sum += arr[i];
// when subarray starts from index '0'
// update maxLength and start and end points
if (sum == k)
{
maxLen = i + 1;
start = 0;
end = i;
}
// make an entry for 'sum' if it is
// not present in 'um'
if (!um.containsKey(sum))
um.put(sum, i);
// check if 'sum-k' is present in 'um'
// or not
if (um.containsKey(sum - k))
{
// update maxLength and start and end points
if (maxLen < (i - um.get(sum - k)))
{
maxLen = i - um.get(sum - k);
start = um.get(sum - k) + 1;
end = i;
}
}
}
// Return true if maximum length is non-zero
return (maxLen != 0);
}
// function to find the largest area rectangular
// sub-matrix whose sum is equal to k
static void sumZeroMatrix(int mat[][], int row,
int col, int k)
{
// Variables to store the temporary values
int []temp = new int[row];
int area;
boolean sum = false;
// Variables to store the final output
int fup = 0, fdown = 0, fleft = 0, fright = 0;
int maxArea = Integer.MIN_VALUE;
// Set the left column
for (int left = 0; left < col; left++)
{
// Initialize all elements of temp as 0
temp = memset(temp, 0);
// Set the right column for the left column
// set by outer loop
for (int right = left; right < col; right++)
{
// Calculate sum between current left
// and right column for every row 'i'
for (int i = 0; i < row; i++)
temp[i] += mat[i][right];
// Find largest subarray with 'k' sum in
// temp[]. The sumEqualToK() function also
// sets values of 'up' and 'down;'. So
// if 'sum' is true then rectangle exists between
// (up, left) and (down, right) which are the
// boundary values.
sum = sumEqualToK(temp, row, k);
area = (end - start + 1) * (right - left + 1);
// Compare no. of elements with previous
// no. of elements in sub-Matrix.
// If new sub-matrix has more elements
// then update maxArea and final boundaries
// like fup, fdown, fleft, fright
if (sum && maxArea < area)
{
fup = start;
fdown = end;
fleft = left;
fright = right;
maxArea = area;
}
}
}
// If there is no change in boundaries
// than check if mat[0][0] equals 'k'
// If it is not equal to 'k' then print
// that no such k-sum sub-matrix exists
if (fup == 0 && fdown == 0 && fleft == 0 &&
fright == 0 && mat[0][0] != k)
{
System.out.print("No sub-matrix with sum "
+ k + " exists");
return;
}
// Print final values
System.out.print("(Top, Left): "
+ "(" + fup+ ", " + fleft
+ ")" +"\n");
System.out.print("(Bottom, Right): "
+ "(" + fdown+ ", " + fright
+ ")" +"\n");
for (int j = fup; j <= fdown; j++)
{
for (int i = fleft; i <= fright; i++)
System.out.print(mat[j][i] + " ");
System.out.println();
}
}
static int[] memset(int []arr, int val)
{
for(int i = 0; i < arr.length; i++)
arr[i] = val;
return arr;
}
// Driver code
public static void main(String[] args)
{
int mat[][] = { { 1, 7, -6, 5 },
{ -8, 6, 7, -2 },
{ 10, -15, 3, 2 },
{ -5, 2, 0, 9 } };
int row = 4, col = 4;
int k = 7;
sumZeroMatrix(mat, row, col, k);
}
}
// This code is contributed by PrinciRaj1992
C#
// C# implementation to find
// the largest area rectangular
// sub-matrix whose sum is equal to k
using System;
using System.Collections.Generic;
class GFG
{
static int MAX = 100;
static int start, end;
// This function basically finds largest 'k'
// sum subarray in arr[0..n-1]. If 'k' sum
// doesn't exist, then it returns false. Else
// it returns true and sets starting and
// ending indexes as start and end.
static bool sumEqualToK(int []arr, int n, int k)
{
// unordered_map 'um' implemented
// as hash table
Dictionary um =
new Dictionary();
int sum = 0, maxLen = 0;
// traverse the given array
for (int i = 0; i < n; i++)
{
// accumulate sum
sum += arr[i];
// when subarray starts from index '0'
// update maxLength and start and end points
if (sum == k)
{
maxLen = i + 1;
start = 0;
end = i;
}
// make an entry for 'sum' if it is
// not present in 'um'
if (!um.ContainsKey(sum))
um.Add(sum, i);
// check if 'sum-k' is present in 'um'
// or not
if (um.ContainsKey(sum - k))
{
// update maxLength and start and end points
if (maxLen < (i - um[sum - k]))
{
maxLen = i - um[sum - k];
start = um[sum - k] + 1;
end = i;
}
}
}
// Return true if maximum length is non-zero
return (maxLen != 0);
}
// function to find the largest area rectangular
// sub-matrix whose sum is equal to k
static void sumZeroMatrix(int [,]mat, int row,
int col, int k)
{
// Variables to store the temporary values
int []temp = new int[row];
int area;
bool sum = false;
// Variables to store the readonly output
int fup = 0, fdown = 0, fleft = 0, fright = 0;
int maxArea = int.MinValue;
// Set the left column
for (int left = 0; left < col; left++)
{
// Initialize all elements of temp as 0
temp = memset(temp, 0);
// Set the right column for the left column
// set by outer loop
for (int right = left; right < col; right++)
{
// Calculate sum between current left
// and right column for every row 'i'
for (int i = 0; i < row; i++)
temp[i] += mat[i, right];
// Find largest subarray with 'k' sum in
// []temp. The sumEqualToK() function also
// sets values of 'up' and 'down;'. So
// if 'sum' is true then rectangle exists between
// (up, left) and (down, right) which are the
// boundary values.
sum = sumEqualToK(temp, row, k);
area = (end - start + 1) * (right - left + 1);
// Compare no. of elements with previous
// no. of elements in sub-Matrix.
// If new sub-matrix has more elements
// then update maxArea and readonly boundaries
// like fup, fdown, fleft, fright
if (sum && maxArea < area)
{
fup = start;
fdown = end;
fleft = left;
fright = right;
maxArea = area;
}
}
}
// If there is no change in boundaries
// than check if mat[0,0] equals 'k'
// If it is not equal to 'k' then print
// that no such k-sum sub-matrix exists
if (fup == 0 && fdown == 0 && fleft == 0 &&
fright == 0 && mat[0, 0] != k)
{
Console.Write("No sub-matrix with sum "
+ k + " exists");
return;
}
// Print readonly values
Console.Write("(Top, Left): "
+ "(" + fup+ ", " + fleft
+ ")" +"\n");
Console.Write("(Bottom, Right): "
+ "(" + fdown+ ", " + fright
+ ")" +"\n");
for (int j = fup; j <= fdown; j++)
{
for (int i = fleft; i <= fright; i++)
Console.Write(mat[j, i] + " ");
Console.WriteLine();
}
}
static int[] memset(int []arr, int val)
{
for(int i = 0; i < arr.Length; i++)
arr[i] = val;
return arr;
}
// Driver code
public static void Main(String[] args)
{
int [,]mat = { { 1, 7, -6, 5 },
{ -8, 6, 7, -2 },
{ 10, -15, 3, 2 },
{ -5, 2, 0, 9 } };
int row = 4, col = 4;
int k = 7;
sumZeroMatrix(mat, row, col, k);
}
}
// This code is contributed by PrinciRaj1992
输出:
(Top, Left): (0, 1)
(Bottom, Right): (2, 3)
7 -6 5
6 7 -2
-15 3 2
时间复杂度: O(n^3)。
辅助空间: O(n)。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。