在此之前,可以先去看看二维数组之二维前缀和首篇和二维数组之前缀和中篇。
最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
class Solution {public int maxSubArray(int[] nums) {int ans = Integer.MIN_VALUE;int max = 0;for(int i = 0;i < nums.length;i++){max = Math.max(nums[i], max + nums[i]);ans = Math.max(ans, max);}return ans;}
}
这道题是比较经典的动态规划问题,但是也比较简单,不慌,设f(i - 1)为以下标i-1结尾连续子数组和的最大值,遍历到下标i时,求以下标i结尾的连续子数组和的最大值,就需要判断nums[i]可以单独成为一段,即以下标i起始的最大子数组和,还是需要加上前面f(i - 1)那一段,而这取决于nums[i]和nums[i]+f(i - 1)的大小关系。
以[-2,1,-3,4,-1,2,1,-5,4]为例子,max表示f(i - 1)为以下标i-1结尾连续子数组和的最大值,ans用于保存以不同下标结尾的连续子数组和的最大值。当i等于0,值为-2,max = -2,ans = -2。当i等于1,值为1,以下标0结尾的连续子数组和的最大值为-2,显然如果1±2没有1大,所以max = 1,ans = 1。当i等于2时,值为-3,以下标1结尾的连续子数组和的最大值为1,-3 + 1 > -3,max = -2,ans = 1。这里可以发现以下标2结尾的连续子数组最大和为-2,因为连续,所以一定要加上-3,以下标2结尾的连续子数组和的最大值小于以下标1结尾的连续子数组和的最大值,所以ans的值还是为1。所以一定要注意max和ans所表示的含义。当i等于3时,值为4,以下标2结尾的连续子数组和的最大值为-2,4 + - 2 = 2 < 4,所以max = 4,ans = 4。如此重复,就能得到最后的答案。
最大子矩阵
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
示例:
输入:
[
[-1,0],
[0,-1]
]
输出:[0,1,0,1]
class Solution {// ans中的值为初始化值,leetcode中矩阵最大长度为200,所以这里默认子矩阵的最大值为整个矩阵值的和int[] ans = new int[]{0, 200, 0, 200};int max = Integer.MIN_VALUE;public int[] getMaxMatrix(int[][] matrix) {int m = matrix.length;int n = matrix[0].length;for(int i = 0;i < m;i++){int[] sum = new int[n];for(int j = i;j < m;j++){for(int k = 0;k < n;k++){sum[k] += matrix[j][k];}maxSubArray(sum, i, j);}}return ans;}// 和一维矩阵求解连续数组最大值的求解方法一样private void maxSubArray(int[] nums, int startCol, int endCol) {int region_max = 0;int startRow = 0;int endRow = 0;for(int i = 0;i < nums.length;i++){if(nums[i] > region_max + nums[i]){startRow = i;endRow = i;region_max = nums[i];}else{endRow = i;region_max += nums[i];}if(region_max > max){max = region_max;ans = new int[]{startCol, startRow, endCol, endRow};}}}
}
这道题可以先将二维数组转化为一维数组,之后利用一维数组求最大子数组和的思路进行求解,将二维数组转化为一维数组,就是合并列。
如上图所示,按行遍历所有可能的行组合,有6种,之后分别计算这6种组合的列和用sum数组表示,这样就得到了一维数组,同时也得到了对应的行起始下标i,和行结束下标j。之后按照一维数组求最大子数组和的方式定位列的起始和结束下标。