2.15 求二维数组的子矩阵的最大和
来源:互联网 发布:linux系统安装方法 编辑:程序博客网 时间:2024/05/17 22:11
1. 前言
本文的一些图片, 资料 截取自编程之美
2. 问题描述
3. 问题分析
对于这种求优问题, 最基本的思路, 无疑便是穷举了
所以 我们这里三种思路, 均为穷举。。。
解法一 : 穷举左上角的点, 然后在穷举所有可能该宽高, 计算矩阵的和, 统计最大值
解法二 : 穷举左上角的点, 然后在穷举所有可能该宽高, 计算矩阵的和, 通过预处理一些数据, 是的这个计算时间复杂度降到O(1)
解法三 : 穷举上下边界, 然后在讲上下边界之间的数字矩阵组合转化为一个一维数组[将每一列的数字之和加起来作为该一位数组的元素], 然后在利用一位数组的解法来解决
编程之美原图 :
4. 代码
/** * file name : Test22FindMaxSumMatrix.java * created at : 2:21:57 PM May 24, 2015 * created by 970655147 */package com.hx.test03;public class Test22FindMaxSumMatrix { // 找到二维数组 子矩阵最大的和 public static void main(String []args) { int[][] intArr = { {1, -1, 1, -1 }, {0, 0, 1, -1 }, {1, 3, 2, 1 }, {1, -2, -1, 0 } }; findMaxSumMatrix01(intArr); findMaxSumMatrix02(intArr); findMaxSumMatrix03(intArr); } // 穷举 public static void findMaxSumMatrix01(int[][] arr) { int max = Integer.MIN_VALUE; for(int row=0; row<arr.length; row++) { for(int col=0; col<arr[0].length; col++) { int maxWidth = arr[0].length - col; int maxHeight = arr.length - row; for(int height=1; height<=maxHeight; height++) { for(int width=1; width<=maxWidth; width++) { int sum = sum(arr, row, col, width, height); if(sum > max) { max = sum; } } } } } Log.log(max); } // 先计算([0][0]) 到([row][col])的矩阵的和存入一个sum矩阵中 // 然后再在 穷举 [计算矩阵中的数据和的方式为 : sum[row+height][col+width] - sum[row+height][col] - sum[row][col+width] + sum[row+height][col] ] private static void findMaxSumMatrix02(int[][] intArr) { int[][] sum = get00ToSpecifiedGridSum(intArr); int max = Integer.MIN_VALUE; for(int row=0; row<intArr.length; row++) { for(int col=0; col<intArr[0].length; col++) { int maxWidth = intArr[0].length - col; int maxHeight = intArr.length - row; for(int height=1; height<=maxHeight; height++) { for(int width=1; width<=maxWidth; width++) { boolean isEnter = false; int tmp = -1; // 先初始化为[row+height-1][col+width-1] // 如果row>0 减去[row+height-1][col] // 如果col>0 减去[row][col+width-1] 如果进入了row>0的判断 说明这里多减了一个[row+height-1][col+width-1] 加回来 tmp = sum[row+height-1][col+width-1]; if(row > 0) { tmp-= sum[row+height-2][col]; isEnter = true; } if(col > 0) { tmp -= sum[row][col+width-2]; if(isEnter) { tmp += sum[row+height-2][col+width-2]; } } if(tmp > max) { max = tmp; } } } } } Log.log(max); } // 枚举上下边界 然后利用一维数组的算法 求解 private static void findMaxSumMatrix03(int[][] intArr) { int max = Integer.MIN_VALUE; for(int up=0; up<intArr.length; up++) { for(int down=up; down<intArr.length; down++) { int[] colArr = getColArrayByRowColWidthHeight(intArr, up, down); int tmp = findMaxSumSeq04(colArr); if(tmp > max) { max = tmp; } } } Log.log(max); } // 从后向前遍历[从前向后也可以] // 初始令start, all为最后一个元素 // 然后向前遍历 取start为intArr[i]和intArr[i]+start的较大者[如果start小于0, 则取intArr[i] ] // 取去all 为当前all, 和当前start子数组之和的最大值 // 如果上一次循环的(start)小于0, 则废弃intArr[lastI], 以及其之前的部分 public static int findMaxSumSeq04(int[] intArr) { int start = intArr[intArr.length-1], all = start; for(int i=intArr.length-2; i>=0; i--) { start = getMax(intArr[i], intArr[i] + start); all = getMax(all, start); } return all; } // 获取x和y之间的较大者 public static int getMax(int x, int y) { return x>y ? x : y; } // 将row, col处, width, height的矩阵转换为一维矩阵, 将同一列视为一个单元 private static int[] getColArrayByRowColWidthHeight(int[][] intArr, int row01, int row02) { int[] res = new int[intArr[0].length]; int idx = 0; for(int col=0; col<res.length; col++) { int sum = 0; for(int row=row01; row<=row02; row++ ) { sum += intArr[row][col]; } res[idx ++] = sum; } return res; } // 计算[0][0]到每一个方格的所有的数之和 // 比如 [1][1] 计算:[0][0], [1][0], [0][1], [1][1] // [1][0] 计算:[0][0], [1][0] private static int[][] get00ToSpecifiedGridSum(int[][] intArr) { int[][] sum = new int[intArr.length][intArr[0].length]; // 计算sum矩阵的第二种方式 // 先初始化 [0][0], 单独计算第一行, 第一列 // 然后在计算之后的[row][col] sum[0][0] = intArr[0][0]; for(int col=1; col<intArr[0].length; col++) { sum[0][col] = sum[0][col-1] + intArr[0][col]; } for(int row=1; row<intArr.length; row++) { sum[row][0] = sum[row][0] + intArr[row][0]; } for(int row=1; row<intArr.length; row++) { sum[row][0] = sum[row-1][0] + intArr[row][0]; for(int col=1; col<intArr[0].length; col++) { // 获取左边的一个方格的sum 在加上当前列([0-row][col])的数据 即为当前方格的sum int tmp = sum[row][col-1]; for(int i=0; i<=row; i++) { tmp += intArr[i][col]; } sum[row][col] = tmp; } } return sum; } // arr中计算row, col为坐标, width, height为宽高的矩阵的和 private static int sum(int[][] arr, int row, int col, int width, int height) { int sum = 0; int maxRow = row + height, maxCol = col + width; for(int i=row; i<maxRow; i++) { for(int j=col; j<maxCol; j++) { sum += arr[i][j]; } } return sum; }}
5. 运行结果
6. 总结
第一种是完全的穷举, 第二种思路则是采用 使用时间换取空间的思路, 将计算矩阵的时间复杂度缩短为O(1), 第三种使用up, down 枚举了上下边界, 累加每一列之和 + findMaxSumSeq04 [O(m)] “枚举了左右边界”
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
0 0
- 2.15 求二维数组的子矩阵的最大和
- 求二维数组最大子数组和(或矩阵的最大子矩阵和)
- 二维数组和最大的子矩阵
- 求矩阵中元素和最大的二维子矩阵
- 【动态规划】求二维矩阵的最大和子矩阵
- 求二维矩阵的最大子矩阵
- 求二维数组中最大子数组的和
- 求二维数组最大子数组的和
- 二维数组最大子矩阵的求和
- 求二维矩阵最大子矩阵和
- 求一个矩阵中最大的二维子矩阵(元素和最大)
- 求一个矩阵中最大的二维子矩阵(元素和最大)
- 最大子矩阵:二维数组的最大连续子数组和
- 求最大子矩阵的和、求最大子数组的和
- 二维数组最大子矩阵和
- 每日一题(81) - 子数组之和的最大值(二维) - 最大子矩阵和
- 求二维数组中子数组和中最大的值,及子数组
- 求子矩阵的最大和
- hdu-5407(多校2015)
- UC-Android逆向工程师 面试题1的分析
- 九度oj 1103
- 第K短路
- golang-发送邮件
- 2.15 求二维数组的子矩阵的最大和
- C语言中do...while(0)的妙用-避免goto
- NYOJ 709 异 形 卵(区域最大值,水题)
- Cin 与 Cout (C++第二天)
- filter2D函数
- inf
- 电脑反应慢的原因
- 拆分整数
- Hibernate 所有缓存机制详解