每日微软面试题——day 8(最大的二维子矩阵)
来源:互联网 发布:smtp服务端口 编辑:程序博客网 时间:2024/04/30 04:21
<以下微软面试题全来自网络>
<以下答案与分析纯属个人观点,不足之处,还望不吝指出^_^>
<版权所有,转载不忘注明出处:http://blog.csdn.net/zhanxinhang,及作者:花心龟的扮演者ZhanHang>
题:求一个矩阵中最大的二维子矩阵(元素和最大).如:
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)。
实现代码:
/**Author:花心龟Blog:http://blog.csdn.net/zhanxinhang**/void get_max_22Matrix(int *a,int row,int col,int *result)//a为原矩阵,row,col指a矩阵的行和列,result存储最终得到的子二维矩阵{ int maxsum=0,result_i,result_j,sum; #define a(i,j) *(a+(i)*col+(j)) //用二维的形式表示一维数组,访问需要一定的代价#define result(i,j) *(result+(i)*2+(j)) 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; result_i = i; result_j = j; } } /* 将结果存储到result二维数组中*/ result(0,0)=a(result_i,result_j); result(1,0)=a(result_i+1,result_j); result(0,1)=a(result_i,result_j+1); result(1,1)=a(result_i+1,result_j+1);#undef a#undef result}
方法二、这是对方法一的改进。分析方法一可知,方法一在每次遍历中,必须同时访问四个元素(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]。
方法二执行步骤与效果图:
实现代码:
/**Author:花心龟Blog:http://blog.csdn.net/zhanxinhang**/void get_max_22Matrix(int *a,int row,int col,int *result){ int maxsum=0,result_i,result_j,sum,last_vsum=0; #define a(i,j) *(a+(i)*col+(j)) #define result(i,j) *(result+(i)*2+(j)) last_vsum = a(0,0)+a(1,0); //初始last_vsum for(int i=0; i<row-1; i++) { for(int j=1; j<col; j++) { sum = last_vsum ; //将last_vsum加入sum last_vsum = a(i,j)+a(i+1,j);//更新last_vsum sum += last_vsum;//将更新后的last_vsum再与sum累加,得到当前子二维矩阵的和 if(maxsum<sum) { maxsum = sum; result_i = i; result_j = j-1; } } } /* 将结果存储到result二维数组中*/ result(0,0)=a(result_i,result_j); result(1,0)=a(result_i+1,result_j); result(0,1)=a(result_i,result_j+1); result(1,1)=a(result_i+1,result_j+1);#undef a#undef result}
方法二与方法一效果对照图:
其中,方法二有中间行需要被访问两次,总共访问次数为5+5+2*5=20次。
而方法一3,4,5元素被访问了4次,总共访问次数为4+2*8+3*4=32次。
方法二与方法一的时间复杂度相同,但是效率要高于方法一,尤其是在大矩阵情况下效果尤为明显
方法三、这可作为对方法二的补充。以上方法二中给的示例矩阵是3*5的矩阵,也就是列大于行的矩阵,但如果是行大于列依然用方法2去执行效果如何呢?效果如下图所示:
5*3矩阵,访问次数为6+2*9=24
可见当行大于列时,利用方法2效果已经下降,如果是大矩阵的话可不只只有4的相差啊。
针对这种情况,只需对方法二稍作改正,没错,就是原先方法二是横向遍历,现在改为纵向遍历,效果如下图所示:
同样是5*3矩阵,访问次数为5+5+2*5=20
又回到了方法2的访问次数。
这样如果是列大于行的矩阵使用方法二,也就是横向遍历
如果是行大于列的矩阵使用方法三,也就纵向遍历
实现代码略。
…………………………………………
赠一测试代码:
int main(){ int a[3*5]={1,2,0,3,4, 2,3,4,5,1, 1,1,5,3,0}; int result[2*2]={0}; get_max_22Matrix(a,3,5,result); #define result(i,j) *(result+(i)*2+(j)) for(int i =0; i<2; i++) { for(int j=0; j<2; j++) printf("%d ",result(i,j)); printf("\n"); } return 0;}
上一篇:每日微软面试题——day 7(找数组中唯一出现两次的数)
- 每日微软面试题——day 8(最大的二维子矩阵)
- 每日微软面试题——day 8(最大的二维子矩阵)
- 每日微软面试题——day 6(打印所有对称子串)
- 每日微软面试题——day 1
- 每日微软面试题——day 2
- 每日微软面试题——day 3
- 每日微软面试题——day 1
- 每日微软面试题——day 5
- 【每日面试题】求一个矩阵中最大的二维矩阵(元素和最大)
- 29. 微软面试题:求一个矩阵中最大的二维矩阵(元素和最大)
- 每日微软面试题——day 7(找数组中唯一出现两次的数)
- 每日微软面试题——day 7(找数组中唯一出现两次的数)
- 【算法】每日微软面试题——day 7(找数组中唯一出现两次的数)
- 每日微软面试题——day 4 (最长等差数列)
- 微软面试题解题笔记——求子数组的最大和
- 腾讯面试题(九度)——面积最大的全1子矩阵
- 经典面试题——二维矩阵子矩阵和问题
- 每日一题(81) - 子数组之和的最大值(二维) - 最大子矩阵和
- ASPX大马得到IIS账户密码跨站
- SQL Server使用触发器删除重复的列(Delete duplicate rows using cursor in SQL Server)
- Delphi官方网站资源
- 万能 dao 增删改查一个方法搞定
- Delphi 过程 和 函数 的基本实例
- 每日微软面试题——day 8(最大的二维子矩阵)
- API HOOK 金山词霸取词功能原理1
- data 5
- swing布局详解(附示例图)(抄录)
- NOSQL Patterns
- 游戏开发之物体的来回移动
- 下位机架构
- 学习方法之笔记
- 不让键盘挡住UITextField