📜  给定2D数组中的最小和子矩阵

📅  最后修改于: 2021-04-23 20:51:54             🧑  作者: Mango

给定2D数组,在其中找到最小和子矩阵。

例子:

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(朴素方法):检查给定2D数组中的每个可能的子矩阵。该解决方案需要4个嵌套循环,并且该解决方案的时间复杂度为O(n ^ 4)。

方法2(有效方法):一维阵列的Kadane算法可用于将时间复杂度降低到O(n ^ 3)。想法是一一固定左列和右列,并为每个左列和右列对找到最小的总和连续行。我们基本上找到了每个固定的左右列对的顶部和底部行号(其总和最小)。要找到顶部和底部的行号,请计算从左到右每一行中元素的总和,并将这些总和存储在一个名为temp []的数组中。因此,temp [i]指示第i行中从左到右的元素总和。如果我们在temp []上应用Kadane的一维算法并获得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


输出:

(Top, Left): (0, 0)
(Bottom, Right): (1, 4)
Minimum sum: -26

时间复杂度:O(n ^ 3)