求一个矩阵中最大的二维子矩阵(元素和最大)

题目:

求一个矩阵中最大的二维子矩阵(元素和最大).如:
          1 2 0 3 4
          2 3 4 5 1
          1 1 5 3 0
          中最大的是:  
          4 5
          5 3
          要求:(1)写出算法;(2)分析时间复杂度;(3)用C写出关键代码

分析方法一、这是最容易想到也是最容易实现的方法。遍历矩阵(行迭代器为i,列迭代器为j),以当前遍历到的元素为首a[i,j],计算二维子矩阵的和(sum=a[i,j]+a[i+1,j]+a[i,j+1]+a[i+1,j+1]),并找出和最大的二维矩阵,注意矩阵的最后一行和最后一列不用遍历。时间复杂度为O(i*j)。

实现代码:

#include <iostream>

using namespace std;

void GetMax2Matrix(int arr[][5], int row, int col, int result[][2])
{
    int max_i = 0;
    int max_j = 0;
    int max_sum = -(1<<31);
    for(int i = 0; i < row-1; i++)
        for(int j = 0; j < col-1; j++)
        {
            int sum = arr[i][j] + arr[i+1][j] + arr[i][j+1] + arr[i+1][j+1];
            if(sum > max_sum)
            {
                max_sum = sum;
                max_i = i;
                max_j = j;
            }
        }
    result[0][0] = arr[max_i][max_j];
    result[0][1] = arr[max_i][max_j+1];
    result[1][0] = arr[max_i+1][max_j];
    result[1][1] = arr[max_i+1][max_j+1];
}
int main(void)
{
    int arr[][5] = {1,2,0,3,4,
                      2,3,4,5,1,
                      1,1,5,3,0};
    int result[2][2];
    GetMax2Matrix(arr, 3, 5, result);
    for(int i = 0; i<2; i++)
        for(int j = 0; j < 2; j++)
            cout<<result[i][j]<<'\t';
    cout<<endl;
    return 0;
}

方法二、这是对方法一的改进。分析方法一可知,方法一在每次遍历中,必须同时访问四个元素(a[i,j],a[i+1,j],a[i,j+1],a[i+1,j+1]),方法一的遍历效果如图所示(用方框框住的表示当前访问到或已访问的元素,元素被框住的次数就越多,表示被访问的次数也就越多,被染的颜色也就越深)。

可从图中看出,方法一中多个元素被重复访问多次,要知道访问一次元素的代价是不容小视的。实际上我们是可以对其进行改进,使每个元素的访问次数尽可能的降低的。改进方法如下:

一、增加一个变量,last_vsum(叫做“最新纵向和”,v是vertical) 且初始化为last_vsum = a[0,0]+a[1,0],其作用将在下面说明。

二、改变遍历方式,原先每次访问四个元素,现在变为每次访问纵向的两个元素(a[i,j],a[i+1,j]),横向遍历,遍历的起始点改为第二个元素,终点到最后一个元素。

三、改变求和方式,求和方法是:首先将上一次保存的和last_vsum加进sum中,再将last_vsum更新为当前纵向的两个元素a[i,j],a[i+1,j]之和,然后再将last_vsum加入sum中,这样就得到本次二维矩阵的和可与maxsum进行比较。如此每次求和只需访问两个元素a[i,j],a[i+1,j]。

方法二执行步骤与效果图:

实现代码:

void GetMax2Matrix2(int arr[][5], int row, int col, int result[][2])
{
    int max_i = 0;
    int max_j = 0;
    int max_sum = -(1<<31);
    
    for(int i = 0; i < row-1; i++)
    {
        int last_sum = arr[i][0] + arr[i+1][0];//每行开始时,初始化last_sum为第一的和,然后从第二列开始 
        for(int j = 1; j < col; j++)
        {
            int sum = last_sum;
            last_sum = arr[i][j] + arr[i+1][j];;
            sum += last_sum;
            if(sum > max_sum)
            {
                max_sum = sum;
                max_i = i;
                max_j = j;
            }
        }
    }

    result[0][0] = arr[max_i][max_j];
    result[0][1] = arr[max_i][max_j+1];
    result[1][0] = arr[max_i+1][max_j];
    result[1][1] = arr[max_i+1][max_j+1];
}
posted @ 2014-03-20 15:53  mickole  阅读(953)  评论(1)    收藏  举报