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

程序员面试金典——解题总结: 9.18高难度题 18.12给定一个正整数和负整数组成的N*M矩阵,编写代码找出元素总和最大的子矩阵。

2017-01-20 18:23 609 查看
#include <iostream>
#include <stdio.h>

using namespace std;
/*
问题:给定一个正整数和负整数组成的N*M矩阵,编写代码找出元素总和最大的子矩阵。
分析:暴力破解:遍历所有子矩阵耗时O(N^4),对每个子矩阵求和耗时O(N^2),总共耗时O(N^6)
动态规划:可以使得对子矩阵求和的时间复杂度降至O(1)。
|A B|  假设左边为矩阵,那么area(D) = ValD - ValB - ValC + ValA
|C D|
时间为O(N^3)的解法:在一维中,最大子序列和可以通过O(N)的动态规划算法求出,而每个子矩阵可以表示未一组连续的行和一组连续的列。
迭代所有连续行的组合,对每一种组合找出一组可以给出元素总和最大的列。
这里的话假设知道行的起始位置和结束位置,可以将行起始位位置和结束位置所在的一列看成一个数字,不断枚举起始列,即可

输入:
2 3(行和列)
1 -2 3
-4 5 6

3 5
9 -8 1 3 -2
-3 7 6 -2 4
6 -4 -4 8 -7
输出:
12
-2 3
5 6

19
9 -8 1 3
-3 7 6 -2
6 -4 -4 8
关键:
1 	  时间为O(N^3)的解法:在一维中,最大子序列和可以通过O(N)的动态规划算法求出,而每个子矩阵可以表示未一组连续的行和一组连续的列。
迭代所有连续行的组合,对每一种组合找出一组可以给出元素总和最大的列。
这里的话假设知道行的起始位置和结束位置,可以将行起始位位置和结束位置所在的一列看成一个数字,不断枚举起始列,即可
2
for(int rowBegin = 0 ; rowBegin < row ; rowBegin++)
{
for(int rowEnd = rowBegin ; rowEnd < row; rowEnd++)
{
int start = getSum(rowBegin , rowEnd , 0 , matrix);
int columnMax = start;//记录在起止行确定的情况下,多个列的最大值
int colBegin = 0;
int colEnd = 0;
//枚举所有的列
for(int i = 1 ; i < column ; i++)
{
//统计起止行所在列的元素总和
if(start < 0)
{
start = getSum(rowBegin , rowEnd , i , matrix);
colBegin = colEnd = i;
}
else
{
start += getSum(rowBegin , rowEnd , i , matrix);
colEnd = i;
}
if(start > columnMax)
{
columnMax = start;
}
if(columnMax > max )
{
max = columnMax;
//需要行的位置
maxRowBegin = rowBegin;
maxRowEnd = rowEnd;
//记录列的起止位置,如果放在列计算最大值的时候更新,会有错误
maxColBegin = colBegin;
maxColEnd = colEnd;
}
}
}
}
*/

const int MAXSIZE = 100;

int getSum(int rowBegin , int rowEnd , int column , int matrix[][MAXSIZE])
{
int result = 0;
if(NULL == matrix || rowEnd < rowBegin || column < 0 || rowBegin < 0)
{
return result;
}
for(int i = rowBegin ; i <= rowEnd ; i++)
{
result += matrix[i][column];
}
return result;
}

//存储最大子矩阵结果:包含最大和,行的起始和结束位置,列的起始和结束位置
class Result
{
public:
Result(){}
int _result;
int _rowBegin;
int _rowEnd;
int _colBegin;
int _colEnd;
};

Result findMaxSumMatrix(int row , int column , int matrix[][MAXSIZE])
{
int max = INT_MIN;
int maxRowBegin = 0 ;
int maxRowEnd = 0;
int maxColBegin = 0;
int maxColEnd = 0;
for(int rowBegin = 0 ; rowBegin < row ; rowBegin++)
{
for(int rowEnd = rowBegin ; rowEnd < row; rowEnd++)
{
int start = getSum(rowBegin , rowEnd , 0 , matrix);
int columnMax = start;//记录在起止行确定的情况下,多个列的最大值
int colBegin = 0;
int colEnd = 0;
//枚举所有的列
for(int i = 1 ; i < column ; i++)
{
//统计起止行所在列的元素总和
if(start < 0)
{
start = getSum(rowBegin , rowEnd , i , matrix);
colBegin = colEnd = i;
}
else
{
start += getSum(rowBegin , rowEnd , i , matrix);
colEnd = i;
}
if(start > columnMax)
{
columnMax = start;
}
if(columnMax > max )
{
max = columnMax;
//需要行的位置
maxRowBegin = rowBegin;
maxRowEnd = rowEnd;
//记录列的起止位置,如果放在列计算最大值的时候更新,会有错误
maxColBegin = colBegin;
maxColEnd = colEnd;
}
}
}
}
Result result;
result._result = max;
result._rowBegin = maxRowBegin;
result._rowEnd = maxRowEnd;
result._colBegin = maxColBegin;
result._colEnd = maxColEnd;
return result;
}

void print(Result& result , int matrix[][MAXSIZE])
{
cout << result._result << endl;
for(int i = result._rowBegin ; i <= result._rowEnd ; i++ )
{
for(int j = result._colBegin ; j <= result._colEnd ; j++)
{
cout << matrix[i][j] << " ";
}
cout << endl;
}
}

void process()
{
int row;
int column;
int gMatrix[MAXSIZE][MAXSIZE];
while(cin >> row >> column)
{
if(row > MAXSIZE || column > MAXSIZE)
{
cout << "row >" << MAXSIZE << ", or column >" << MAXSIZE;
continue;
}
memset(gMatrix , 0 , sizeof(gMatrix));
for(int i = 0 ; i < row ; i++ )
{
for(int j = 0 ; j < column ; j++)
{
cin >> gMatrix[i][j];
}
}
Result result = findMaxSumMatrix(row , column , gMatrix);
print(result , gMatrix);
}
}

int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐