给定一个二维数组,找出其中的最小和子矩阵。
例子:
Input : M[][] = {{1, 2, -1, -4, -20},
{-8, -3, 4, 2, 1},
{3, 8, 10, 1, 3},
{-4, -1, 1, 7, -6}}
Output : -26
Submatrix starting from (Top, Left): (0, 0)
and ending at (Bottom, Right): (1, 4) indexes.
The elements are of the submtrix are:
{ {1, 2, -1, -4, -20},
{-8, -3, 4, 2, 1} } having sum = -26
方法 1(朴素方法):检查给定二维数组中的每个可能的子矩阵。该解决方案需要 4 个嵌套循环,并且该解决方案的时间复杂度为 O(n^4)。
方法二(Efficient Approach):可以使用Kadane的一维数组算法,将时间复杂度降低到O(n^3)。这个想法是将左右列一一固定,并为每个左右列对找到最小总和的连续行。我们基本上找到每个固定的左右列对的顶部和底部行号(具有最小总和)。要找到顶部和底部的行号,请从左到右计算每行中元素的总和,并将这些总和存储在一个数组中,比如 temp[]。所以 temp[i] 表示第 i 行从左到右的元素总和。如果我们在 temp[] 上应用 Kadane 的 1D 算法并获得 temp 的最小和子数组,那么这个最小和就是以左右为边界列的最小可能和。为了获得总体最小总和,我们将此总和与迄今为止的最小总和进行比较。
C++
// C++ implementation to find minimum sum
// submatrix in a given 2D array
#include
using namespace std;
#define ROW 4
#define COL 5
// Implementation of Kadane's algorithm for
// 1D array. The function returns the miniimum
// sum and stores starting and ending indexes
// of the minimum sum subarray at addresses
// pointed by start and finish pointers
// respectively.
int kadane(int* arr, int* start, int* finish,
int n)
{
// initialize sum, maxSum and
int sum = 0, minSum = INT_MAX, i;
// Just some initial value to check for
// all negative values case
*finish = -1;
// local variable
int local_start = 0;
for (i = 0; i < n; ++i) {
sum += arr[i];
if (sum > 0) {
sum = 0;
local_start = i + 1;
} else if (sum < minSum) {
minSum = sum;
*start = local_start;
*finish = i;
}
}
// There is at-least one non-negative number
if (*finish != -1)
return minSum;
// Special Case: When all numbers in arr[]
// are positive
minSum = arr[0];
*start = *finish = 0;
// Find the minimum element in array
for (i = 1; i < n; i++) {
if (arr[i] < minSum) {
minSum = arr[i];
*start = *finish = i;
}
}
return minSum;
}
// function to find minimum sum submatrix
// in a given 2D array
void findMinSumSubmatrix(int M[][COL])
{
// Variables to store the final output
int minSum = INT_MAX, finalLeft, finalRight,
finalTop, finalBottom;
int left, right, i;
int temp[ROW], sum, start, finish;
// Set the left column
for (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 (right = left; right < COL; ++right) {
// Calculate sum between current left
// and right for every row 'i'
for (i = 0; i < ROW; ++i)
temp[i] += M[i][right];
// Find the minimum sum subarray in temp[].
// The kadane() function also sets values
// of start and finish. So 'sum' is sum of
// rectangle between (start, left) and
// (finish, right) which is the minimum sum
// with boundary columns strictly as
// left and right.
sum = kadane(temp, &start, &finish, ROW);
// Compare sum with maximum sum so far. If
// sum is more, then update maxSum and other
// output values
if (sum < minSum) {
minSum = sum;
finalLeft = left;
finalRight = right;
finalTop = start;
finalBottom = finish;
}
}
}
// Print final values
cout << "(Top, Left): (" << finalTop << ", "
<< finalLeft << ")\n";
cout << "(Bottom, Right): (" << finalBottom << ", "
<< finalRight << ")\n";
cout << "Minimum sum: " << minSum;
}
// Driver program to test above
int main()
{
int M[ROW][COL] = { { 1, 2, -1, -4, -20 },
{ -8, -3, 4, 2, 1 },
{ 3, 8, 10, 1, 3 },
{ -4, -1, 1, 7, -6 } };
findMinSumSubmatrix(M);
return 0;
}
Java
/*package whatever //do not write package name here */
import java.io.*;
import java.util.*;
class GFG
{
static int ROW = 4;
static int COL = 5;
static int start;
static int finish;
static int kadane(int[] arr, int n)
{
// initialize sum, maxSum and
int sum = 0, minSum = Integer.MAX_VALUE, i;
// Just some initial value to check for
// all negative values case
finish = -1;
// local variable
int local_start = 0;
for (i = 0; i < n; ++i)
{
sum += arr[i];
if (sum > 0)
{
sum = 0;
local_start = i + 1;
}
else if (sum < minSum)
{
minSum = sum;
start = local_start;
finish = i;
}
}
// There is at-least one non-negative number
if (finish != -1)
return minSum;
// Special Case: When all numbers in arr[]
// are positive
minSum = arr[0];
start = finish = 0;
// Find the minimum element in array
for (i = 1; i < n; i++)
{
if (arr[i] < minSum)
{
minSum = arr[i];
start = finish = i;
}
}
return minSum;
}
// function to find minimum sum submatrix
// in a given 2D array
static void findMinSumSubmatrix(int[][] M)
{
// Variables to store the final output
int minSum = Integer.MAX_VALUE;
int finalLeft = 0 , finalRight = 0, finalTop = 0, finalBottom = 0;
int left, right, i;
int []temp= new int[ROW];
int sum;
// Set the left column
for (left = 0; left < COL; ++left)
{
// Initialize all elements of temp as 0
Arrays.fill(temp, 0);
// Set the right column for the left
// column set by outer loop
for (right = left; right < COL; ++right)
{
// Calculate sum between current left
// and right for every row 'i'
for (i = 0; i < ROW; ++i)
temp[i] += M[i][right];
// Find the minimum sum subarray in temp[].
// The kadane() function also sets values
// of start and finish. So 'sum' is sum of
// rectangle between (start, left) and
// (finish, right) which is the minimum sum
// with boundary columns strictly as
// left and right.
sum = kadane(temp, ROW);
// Compare sum with maximum sum so far. If
// sum is more, then update maxSum and other
// output values
if (sum < minSum)
{
minSum = sum;
finalLeft = left;
finalRight = right;
finalTop = start;
finalBottom = finish;
}
}
}
// Print final values
System.out.println("(Top, Left): (" +
finalTop + ", " +
finalLeft + ")");
System.out.println("(Bottom, Right): (" +
finalBottom + ", " +
finalRight + ")");
System.out.println("Minimum sum: "+ minSum);
}
// Driver program to test above
public static void main (String[] args)
{
int[][] M ={{ 1, 2, -1, -4, -20 },
{ -8, -3, 4, 2, 1 },
{ 3, 8, 10, 1, 3 },
{ -4, -1, 1, 7, -6 }};
findMinSumSubmatrix(M);
}
}
// This code is contributed by avanitrachhadiya2155
Python3
# Python3 implementation to find minimum
# sum submatrix in a given 2D array
import sys
# Implementation of Kadane's algorithm for
# 1D array. The function returns the miniimum
# sum and stores starting and ending indexes
# of the minimum sum subarray at addresses
# pointed by start and finish pointers
# respectively.
def kadane(arr, start, finish, n):
# Initialize sum, maxSum and
sum, minSum = 0, sys.maxsize
# Just some initial value to check
# for all negative values case
finish = -1
# Local variable
local_start = 0
for i in range(n):
sum += arr[i]
if (sum > 0):
sum = 0
local_start = i + 1
elif (sum < minSum):
minSum = sum
start = local_start
finish = i
# There is at-least one non-negative number
if (finish != -1):
return minSum, start, finish
# Special Case: When all numbers in arr[]
# are positive
minSum = arr[0]
start, finish = 0, 0
# Find the minimum element in array
for i in range(1, n):
if (arr[i] < minSum):
minSum = arr[i]
start = finish = i
return minSum, start, finish
# Function to find minimum sum submatrix
# in a given 2D array
def findMinSumSubmatrix(M):
# Variables to store the final output
minSum = sys.maxsize
finalLeft = 0
finalRight = 0
finalTop = 0
finalBottom = 0
#left, right, i = 0, 0, 0
sum, start, finish = 0, 0, 0
# Set the left column
for left in range(5):
# Initialize all elements of temp as 0
temp = [0 for i in range(5)]
# Set the right column for the left
# column set by outer loop
for right in range(left, 5):
# Calculate sum between current left
# and right for every row 'i'
for i in range(4):
temp[i] += M[i][right]
# Find the minimum sum subarray in temp[].
# The kadane() function also sets values
# of start and finish. So 'sum' is sum of
# rectangle between (start, left) and
# (finish, right) which is the minimum sum
# with boundary columns strictly as
# left and right.
sum, start, finish = kadane(temp, start,
finish, 4)
# Compare sum with maximum sum so far. If
# sum is more, then update maxSum and other
# output values
if (sum < minSum):
minSum = sum
finalLeft = left
finalRight = right
finalTop = start
finalBottom = finish
# Print final values
print("(Top, Left): (", finalTop,
",", finalLeft, ")")
print("(Bottom, Right): (", finalBottom,
",", finalRight, ")")
print("Minimum sum:", minSum)
# Driver code
if __name__ == '__main__':
M = [ [ 1, 2, -1, -4, -20 ],
[ -8, -3, 4, 2, 1 ],
[ 3, 8, 10, 1, 3 ],
[ -4, -1, 1, 7, -6 ] ]
findMinSumSubmatrix(M)
# This code is contributed by mohit kumar 29
C#
using System;
public class GFG
{
static int ROW = 4;
static int COL = 5;
static int start;
static int finish;
static int kadane(int[] arr, int n)
{
// initialize sum, maxSum and
int sum = 0, minSum = Int32.MaxValue, i;
// Just some initial value to check for
// all negative values case
finish = -1;
// local variable
int local_start = 0;
for (i = 0; i < n; ++i)
{
sum += arr[i];
if (sum > 0)
{
sum = 0;
local_start = i + 1;
}
else if (sum < minSum)
{
minSum = sum;
start = local_start;
finish = i;
}
}
// There is at-least one non-negative number
if (finish != -1)
return minSum;
// Special Case: When all numbers in arr[]
// are positive
minSum = arr[0];
start = finish = 0;
// Find the minimum element in array
for (i = 1; i < n; i++)
{
if (arr[i] < minSum)
{
minSum = arr[i];
start = finish = i;
}
}
return minSum;
}
// function to find minimum sum submatrix
// in a given 2D array
static void findMinSumSubmatrix(int[,] M)
{
// Variables to store the final output
int minSum = Int32.MaxValue;
int finalLeft = 0 , finalRight = 0, finalTop = 0, finalBottom = 0;
int left, right, i;
int []temp= new int[ROW];
int sum;
// Set the left column
for (left = 0; left < COL; ++left)
{
// Initialize all elements of temp as 0
Array.Fill(temp, 0);
// Set the right column for the left
// column set by outer loop
for (right = left; right < COL; ++right)
{
// Calculate sum between current left
// and right for every row 'i'
for (i = 0; i < ROW; ++i)
temp[i] += M[i, right];
// Find the minimum sum subarray in temp[].
// The kadane() function also sets values
// of start and finish. So 'sum' is sum of
// rectangle between (start, left) and
// (finish, right) which is the minimum sum
// with boundary columns strictly as
// left and right.
sum = kadane(temp, ROW);
// Compare sum with maximum sum so far. If
// sum is more, then update maxSum and other
// output values
if (sum < minSum)
{
minSum = sum;
finalLeft = left;
finalRight = right;
finalTop = start;
finalBottom = finish;
}
}
}
Console.WriteLine("(Top, Left): (" +
finalTop + ", " +
finalLeft + ")");
Console.WriteLine("(Bottom, Right): (" +
finalBottom + ", " +
finalRight + ")");
Console.WriteLine("Minimum sum: "+ minSum);
}
// Driver program to test above
static public void Main ()
{
int[,] M ={{ 1, 2, -1, -4, -20 },
{ -8, -3, 4, 2, 1 },
{ 3, 8, 10, 1, 3 },
{ -4, -1, 1, 7, -6 }};
findMinSumSubmatrix(M);
}
}
// This code is contributed by rag2127
Javascript
输出:
(Top, Left): (0, 0)
(Bottom, Right): (1, 4)
Minimum sum: -26
时间复杂度:O(n^3)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。