您的位置:首页 > 职场人生

微软面试100题系列---最大二维子矩阵和

2016-09-04 22:15 309 查看

题目

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

实现

方法1

思路:遍历每个二维矩阵,记录最大的和;时间复杂度o(mn);

代码:

public static void Max2DMatrix(int[][] A,int row,int col){
int maxSum=0;
int sum=0;
int res_i=0,res_j=0;
for(int i=0;i<row-1;i++){
for(int j=0;j<col-1;j++){
sum=A[i][j]+A[i+1][j]+A[i][j+1]+A[i+1][j+1];
if(maxSum<sum){
maxSum=sum;
res_i=i;
res_j=j;
}
}
}
result[0][0]=A[res_i][res_j];
result[0][1]=A[res_i][res_j+1];
result[1][0]=A[res_i+1][res_j];
result[1][1]=A[res_i+1][res_j+1];
}


方法2

对方法1进行分析,方法1在每次遍历时,必须同时访问4个元素,如图所示:



从图中可以看出,多个元素被重复访问多次。

我们对其进行改进,使每个元素的访问次数尽可能的减少。改进方法如下:

1)增加一个变量last_vsum(最新纵向和),初始化为
A[0][0]+A[1][0]
;

2)改变遍历方式,每次遍历只访问纵向的2个元素A[i][j]和A[i+1][j];横向遍历的起始点从第二列开始;

3)改变求和方式,求和方法:将上次保存的last_vsum+A[i][j]+A[i+1][j];last_vsum=A[i][j]+A[i+1][j];

这样可以减少某些元素的访问次数;

代码实现:

public static void Max2DMatrix_2(int[][] A,int row,int col){
int last_vsum=A[0][0]+A[1][0];
int maxSum=0;
int sum=0;
int res_i=0,res_j=0;
for(int i=0;i<row-1;i++){
for(int j=1;j<col;j++){
sum=last_vsum;
last_vsum=A[i][j]+A[i+1][j];
sum+=last_vsum;
if(maxSum<sum){
maxSum=sum;
res_i=i;
res_j=j-1;
}
}
}

result[0][0]=A[res_i][res_j];
result[0][1]=A[res_i][res_j+1];
result[1][0]=A[res_i+1][res_j];
result[1][1]=A[res_i+1][res_j+1];
}


方法2与方法1的时间复杂度相同,但效率高,尤其在大矩阵情况下。但是当矩阵的行数大于列数,方法2效率下降;

===》如果列大于行,使用方法2—横向遍历;

如果列小于行,使用–纵向遍历;

扩展

要求求出最大的子矩阵。

分析:

这是一维最大字串的二维扩展问题。

一维最大字串(最大连续子数组和)问题–动态规划:

b[i]–表示包含a[i]的子数组和;b[i]=max{b[i-1]+a[i],a[i]};

将最大字串应用到该题目中,步骤:

1)压缩列

将每列自上向下做累加,存入b[i][j]中;b[i][j]表示第j列,自第一行到第i行的和;

对于第j列,从第i行到第k行的和:b[k][j]-b[i][j];

2)DP列

得到b后,对b求最大子数组和问题;b是一维的;

然后循环DP,总共三层循环:

最外层i从1-n,表明子矩阵从第i行到第开始累加的;

第二层j从i-n,表明子矩阵从第i行累加到第j行;

第三层k从1到m做DP;

代码实现

public static int maxSubMatrix(int[][] A,int row,int col){
int[] b=new int[col];
int i,j,k;
int max=0,sum=Integer.MIN_VALUE;

for(i=0;i<row;i++){
for(k=0;k<col;k++){
b[k]=0;
}
for(j=i;j<row;j++){//从i行到j行的和;先是第i行(1行);然后从i到i+1(2行),依次求,最后从i到j行的和;每求一次得到一个b的一维数组,然后对该数组求最大连续子数组和(子矩阵的和),判断是否比当前维护的最大子矩阵和大;--从第i行开始依次压缩列,压缩1列/压缩2列...;
for(k=0;k<col;k++){
b[k]+=A[j][k];
}
max=maxSubArray(col,b);
if(max>sum){
sum=max;
}
}
}
return sum;
}

public static int maxSubArray(int  n,int[] a){
int b=0;
int sum<
4000
/span>=Integer.MIN_VALUE;
for(int i=0;i<n;i++){
if(b>0){
b+=a[i];
}else{
b=a[i];
}
if(b>sum){
sum=b;
}
}
return sum;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: