微软面试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; }
相关文章推荐
- 【从零单排之微软面试100题系列】11之二叉树中结点的最大距离
- 微软面试100题系列-数组连续和最大
- 微软面试100题系列---求二叉树中节点的最大距离
- 微软面试100题系列---求子数组的最大和
- 【从零单排之微软面试100题系列】03之求子数组的最大和
- 微软等公司数据结构+算法面试100题系列(61——100题)
- 永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]
- 永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]
- 网友答案整理I:微软等面试100题系列之网友精彩回复 [一]
- 微软面试100题系列:一道合并链表问题的解答[第42题]
- 永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]
- 永久勘误:微软等面试100题系列,答案V0.3版[第21-40题答案]
- 微软面试100系列 第32题
- 网友答案整理II:微软等面试100题系列之网友精彩回复 [二]
- 微软等面试100题系列 29题解答 望各位同行指导
- 网友答案整理I:微软等面试100题系列之网友精彩回复 [一]
- 网友答案整理II:微软等面试100题系列之网友精彩回复 [二]
- 微软面试100题系列:一道合并链表问题的解答[第42题]
- 永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]
- 微软等数据结构+算法面试100题(15)--求最大连续递增数字串