给出一个 m*n 的二维数组(元素可为正可为负),求该二维数组的一个子数组,且此子数组中所有元素的和最大,并输出该数组的和。
给出一个 m*n 的二维数组(元素可为正可为负),求该二维数组的一个子数组,且此子数组中所有元素的和最大,并输出该数组的和
——刘铸辉 何晓楠
思路:
先枚举子数组再将其压缩成一维数组求其值并比较出最大值输出
方法:
若从第i行开始,到第j行结束的数组中子数组的最大和
为了求 我们对这个数组(第i行开始,到第j行结束的数组)进行处理:
(1)把这个数组中的每一列数相加,最后形成一个一维数组,其长度等于原二维数组列的个数。
(2)在该一维数组上,求解最大子数组和。
这是从网上找的 不是自己写的 ,不过感觉这个程序还行,不过在压缩时每列相加的一维数组有点浪费时间,所以优化了一下: 在 给出一个二维子矩阵后,为了更快地求出其对应的一维矩阵, 使用二维数组sum[x][y]预先保存第y列,从第0行到第x行之间元素之和。这样他的时间复杂度就减少了,花的时间少了。 原来的时间复杂度O((m*n)^2),
现在的时间复杂度为O(m*m*n)。这里就直接给出优化后的代码大家:可以看下
把原矩阵第i行和第j行之间元素进行压缩,形成一个一维数组
void InitSumArr(int** pnArr,int** pnArrColSum,int nXLen,int nYLen) { assert(pnArr && *pnArr && pnArrColSum && *pnArrColSum); assert(nXLen > 0 && nYLen > 0); for (int i = 0;i < nXLen;i++)//横坐标 { for (int j = 0;j < nYLen;j++)//纵坐标 { pnArrColSum[i][j] = 0; for (int t = 0;t <= i;t++) { pnArrColSum[i][j] += pnArr[t][j]; } } } }
枚举二维数组,压缩成一维数组,求解最大子数组和
int MaxSubMatrixSum(int** pnArr,int** pnArrColSum,int nXLen,int nYLen) { assert(pnArr && *pnArr && pnArrColSum && *pnArrColSum); assert(nXLen > 0 && nYLen > 0); int nMaxSum = -0x3f3f3f3f; int nCurSum = -0x3f3f3f3f; int* pTmpArr = new int[nYLen]; for (int i = 0;i < nXLen;i++) { for (int j = i;j < nXLen;j++) { if (i == 0) { for (int t = 0;t < nYLen;t++) { pTmpArr[t] = pnArrColSum[j][t]; } nCurSum = MaxSubSum(pTmpArr,nYLen); nMaxSum = max(nCurSum,nMaxSum); } else { //计算每列元素和,并求最大子数组之和 for (int t = 0;t < nYLen;t++) { pTmpArr[t] = pnArrColSum[j][t] - pnArrColSum[i - 1][t]; } nCurSum = MaxSubSum(pTmpArr,nYLen); nMaxSum = max(nCurSum,nMaxSum); } } } return nMaxSum; }
虽然这不是我们自己写的,但我和辉哥也学会了二维数组如何寻找最大子数组,一开始也没想到,嘿嘿 ,惭愧啊,不过这次记住了,还是有收获的。