二维数组之前缀和下篇

        在此之前,可以先去看看二维数组之二维前缀和首篇二维数组之前缀和中篇

最大子数组和

给你一个整数数组 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。之后按照一维数组求最大子数组和的方式定位列的起始和结束下标。

  • 34
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值