免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6955 | 回复: 5
打印 上一主题 下一主题

[算法] 【已解决】面试题: 如何求出一个2维矩阵中,子矩阵最大的元素之和? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-07-31 13:48 |只看该作者 |倒序浏览
本帖最后由 ejeker 于 2013-08-01 09:09 编辑

今天被问到了这道题。这道题分为两个部分:
(1) 如何求一个数组中最大的子数组的和?
       这一问比较简单,网上都讨论的比较多了。我很快写出了程序代码。一次遍历数组就行了O(n),空前需要N(2)

  1. int f(int* pi,size_t num){
  2.         int sum=0;
  3.         int cur=0;
  4.         for(size_t i=0;i<num;++i)
  5.         {
  6.                 cur+=pi[i];
  7.                 if(cur<0)
  8.                 {
  9.                         cur=0;
  10.                 }
  11.                 if(sum<cur)
  12.                 {
  13.                         sum=cur;
  14.                 }
  15.         }
  16.         return sum;
  17. }
  18. int main(int argc, char * argv[])
  19. {
  20.         int buf[]={2,-1,3,9,-2,1,3,-1};
  21.         int s=f(buf,sizeof(buf)/sizeof(int));
  22.         return 0;
  23. }
复制代码
结果是s=15

(2) 根据(1)的思路,如何求出一个2维矩阵中,子矩阵最大的元素之和?
例如有矩阵:
1  3 -7 9
2  7  8 -2
1  9  4 -1
-3 1 -5 2

非常明显,元素之和最大的子矩阵是:
2 7 8
1 9 4
那么元素和是31

如何能用最佳的方法求得31呢?

显然,用穷举的方法可以,但是这需要O(n^4)的计算复杂度。既然第(1)问可以用O(n)来解决,那么本问题是否可以用O(n^2)或者更好的方式解决?

如何设计这样的一个算法?

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2013-07-31 13:55 |只看该作者
例如有矩阵:
1  3 -7 9
2  7  8  2
1  9  4 -1
-3 1 -5 2

非常明显,元素之和最大的子矩阵是:
2 7 8
1 9 4

------------- 不对吧,如果将右边的 2, -1 也包括进来,其元素和就能增1

论坛徽章:
0
3 [报告]
发表于 2013-07-31 14:00 |只看该作者
bruceteen 发表于 2013-07-31 13:55
例如有矩阵:
1  3 -7 9
2  7  8 2


更正一下,第二排最后一个是-2

1  3 -7 9
2  7  8 -2

上面已经改过了。谢谢。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
4 [报告]
发表于 2013-07-31 14:18 |只看该作者
1  3 -7 9
2  7  8  2
1  9  4 -1
很显然,这个更大

论坛徽章:
0
5 [报告]
发表于 2013-07-31 14:30 |只看该作者
cjaizss 发表于 2013-07-31 14:18
1  3 -7 9
2  7  8  2
1  9  4 -1


嗯,我说的有失误的地方,肯定被鄙视了,汗啊。

如何找到一个最优化的算法呢?

论坛徽章:
0
6 [报告]
发表于 2013-07-31 15:51 |只看该作者
有个O(n^3)的算法:

枚举起始行和终止行,枚举个数一共有C(4,2)=6个。
A[0]就是原数组从起始行到终止行的第0列数组之和,那么A[0]一共有6个可能值,复杂度共O(n^2)
A[0,1]=3 第1行到第2行
A[0,2]=4 第1行到第3行
A[0,3]=1 第1行到第4行
A[0,4]=3 第2行到第3行
A[0,5]=0 第2行到第4行
A[0,6]=2 第3行到第4行

然后求出A[1]到A[5]。至此复杂度是O(n^3).
然后对于每个起始行和终止行的情况,求A的线型最大,也就是A[0,1],A[1,1],A[2,1],A[3,1],A[4,1],A[5,1]作为一个数组求一次线性最大,得到从第一行到第二行的子矩阵的最大子子矩阵元素和。

共求了N次线型最大,共花费O(n^2).
二者相加,因此最终的复杂度是O(n^3)。

之所以不用O(n^4)相当于算法本身保存了一部分运算的结果了。

我觉得计算的过程还可以优化一下,例如,如果我们知道了[1,2][2,3][3,4]这几个起始/终止行的组合,就能得到[1,3],[1,4],[2,4]这几个和,少了一些运算。但是我不可能这样能否就从O(n^3)降到了O(n^2)或者O(n^2 lgn)
那么,可不可能比O(n^3)更小呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP