程序员面试金典——解题总结: 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; }
相关文章推荐
- 给定一个正整数和负整数组成的N*N矩阵,编写代码找出元素总和最大的子矩阵。
- 程序员面试金典——解题总结: 9.18高难度题 18.7给定一组单词,编写一个程序,找出其中的最长单词,且该单词由这组单词中的其他单词组合而成。
- 程序员面试金典——解题总结: 9.18高难度题 18.11给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出四条边都是黑色像素的最大子方阵。
- 程序员面试金典——解题总结: 9.18高难度题 18.13给定一份几百万个单词的清单,设计一个算法,创建由字母组成的最大矩形
- 程序员面试金典——解题总结: 9.18高难度题 18.6设计一个算法,给定10亿数字,找出最小的100万个数字。假定计算机内存足以容纳全部10亿个数字。
- 程序员面试金典——解题总结: 9.18高难度题 18.9随机生成一些数字并传入某个方法。编写一个程序,每当收到新数字时,找出并记录中位数。
- 程序员面试金典——解题总结: 9.17中等难题 17.8给定一个整数数组(有正数有负数),找出总和最大的连续数列,并返回总和
- 程序员面试金典——解题总结: 9.18高难度题 18.10给定两个字典里的单词,长度相等。编写一个方法,将一个单词变换成另一个单词,一次只改动一个字母。
- 程序员面试金典——解题总结: 9.17中等难题 17.6给定一个整数数组,编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n - m越小越好,也就是说,找出
- 程序员面试金典——解题总结: 9.18高难度题 18.3编写一个方法,从大小为n的数组中随机选出m个整数。要求每个元素被选中的概率相同。
- 程序员面试金典——解题总结: 9.18高难度题 18.4编写一个方法,数出0到n(含)中数字2出现了几次
- 给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。
- 程序员面试金典: 9.11 排序与查找 11.6给定M*N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。
- 程序员面试金典——解题总结: 9.18高难度题 18.1编写一个函数,将两个数字相加。不得使用+或其他算术运算符。
- 程序员面试金典——解题总结: 9.18高难度题 18.2编写一个方法,洗一副牌。要求做到完美洗牌,换言之,这副牌52!种排列组合出现的概率相同
- 程序员面试金典——解题总结: 9.18高难度题 18.5有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离
- 程序员面试金典——解题总结: 9.18高难度题 18.8给定一个字符串s和一个包含较短字符串的数组T,设计一个方法,根据T中的每一个较短字符串,对s进行搜索
- 程序员面试金典——解题总结: 9.17中等难题 17.4编写一个方法,找出两个数字中最大的那一个。不得使用if-else或其他比较运算符。
- 给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次,编写代码找出数组中的某个元素
- 给定M*N矩阵,编写代码找出某元素