华为OD机试 - 最大矩阵和 - 卡德恩算法(动态规划)(Java 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题(E卷+D卷+A卷+B卷+C卷)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

给定一个二维整数矩阵,要在这个矩阵中选出一个子矩阵,使得这个子矩阵内所有的数字和尽量大。我们把这个子矩阵称为最大子矩阵,子矩阵的选取原则是原矩阵中一块相互连续的矩形区域。

二、输入描述

输入的第一行包含2个整数n, m (1 <= n, m <= 10),表示一个n行m列的矩阵,下面有n行,每行有m个整数,同一行中,每2个数字之间有1个空格,最后一个数字后面没有空格。所有的数字的在[-1000, 1000]之间。

三、输出描述

输出一行一个数字,表示选出的和最大的子矩阵内所有的数字和。## 四、测试用例

测试用例1:

1、输入

3 4
-3 5 -1 5
2 4 -2 4
-1 3 -1 3

2、输出

20

3、说明

选出的和最大的子矩阵是后3列的所有行,其和为:

5 -1 5
4 -2 4
3 -1 3

和为:(5 + (-1) + 5 + 4 + (-2) + 4 + 3 + (-1) + 3) = 20

测试用例2:

1、输入

4 4
-1 -1 -1 -1
-1 2 2 -1
-1 2 2 -1
-1 -1 -1 -1

2、输出

8

3、说明

选出的和最大的子矩阵是中间2x2的矩阵,即:

2 2
2 2

和为:(2 + 2 + 2 + 2) = 8

五、解题思路

1、问题理解

给定一个二维整数矩阵,要求选出一个矩形区域(子矩阵),使得其中的数字和尽可能大。这个问题可以看作是一个二维最大子数组和问题的扩展版本,类似于在一维数组中找到最大子数组和的问题。

2、卡德恩算法

卡德恩算法的核心思想是使用动态规划,通过维护一个局部最优解来逐步构造全局最优解,在一维数组中找到和最大的连续子数组。

一维数组中寻找最大子数组和的经典算法。时间复杂度为O(n),动态规划思想通过记录当前的最大和,逐步遍历数组并更新全局最大值。
在二维矩阵中,可以通过固定上下边界,将二维问题转化为多个一维问题,并用Kadane’s算法在每个转换后的一维数组中求解最大子数组和。

3、具体步骤:

  1. 通过固定上下边界,将二维问题化简为多个一维问题。具体来说,对于每对上下边界top和bottom,计算边界内每一列的和,形成一个一维数组temp。
  2. 然后对该一维数组temp使用Kadane’s算法,求出这一维数组中的最大子数组和,这相当于当前上下边界之间的最大子矩阵和。
  3. 不断枚举所有可能的上下边界,并记录全局最大值。

4、时间复杂度

枚举上下边界的时间复杂度为O(n2),每次求解一维子数组和的时间复杂度为O(m),因此总时间复杂度为O(n2 * m)。由于n和m均不超过10,算法复杂度是可以接受的。

5、空间复杂度

需要一个大小为m的临时数组temp[]来存储每次上下边界之间的列和。除此之外,算法没有额外的空间开销,空间复杂度为O(m)。

六、Java算法源码

public class OdTest01 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 读取矩阵的行数和列数
        int n = sc.nextInt(); // 行数
        int m = sc.nextInt(); // 列数

        int[][] matrix = new int[n][m];

        // 读取矩阵
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                matrix[i][j] = sc.nextInt();
            }
        }

        // 计算最大子矩阵的和
        System.out.println(maxSubmatrixSum(matrix, n, m));
    }

    // 使用Kadane's算法扩展版来求解最大子矩阵的和
    private static int maxSubmatrixSum(int[][] matrix, int n, int m) {
        int maxSum = Integer.MIN_VALUE;  // 初始化最大和为最小值

        // 临时数组,用来存储每一列的和
        int[] temp = new int[m];

        // 枚举每一对上下边界
        for (int top = 0; top < n; top++) {
            // 清空temp数组,重新计算
            for (int i = 0; i < m; i++) {
                temp[i] = 0;
            }

            // 枚举下边界
            for (int bottom = top; bottom < n; bottom++) {
                // 累加每一列的元素
                for (int i = 0; i < m; i++) {
                    temp[i] += matrix[bottom][i];
                }

                // 使用Kadane's算法找出一维数组的最大子数组和
                int currentMaxSum = kadane(temp, m);

                // 更新全局最大和
                maxSum = Math.max(maxSum, currentMaxSum);
            }
        }

        return maxSum;
    }

    // Kadane算法,求一维数组的最大子数组和
    private static int kadane(int[] array, int size) {
        int maxEndingHere = array[0];
        int maxSoFar = array[0];

        for (int i = 1; i < size; i++) {
            // 动态规划,比较当前元素和之前的最大和
            maxEndingHere = Math.max(array[i], maxEndingHere + array[i]);
            // 更新全局最大和
            maxSoFar = Math.max(maxSoFar, maxEndingHere);
        }

        return maxSoFar;
    }
}

七、效果展示

1、输入

3 3
0 1 0
1 1 1
0 1 0

2、输出

5

3、说明

矩阵如下:

0 1 0
1 1 1
0 1 0

选出的和最大的子矩阵是整个矩阵,和为:0 + 1 + 0 + 1 + 1 + 1 + 0 + 1 + 0 = 5

在这里插入图片描述


🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2024 E卷 200分)

🏆本文收录于,华为OD机试(JAVA)真题(E卷+D卷+A卷+B卷+C卷)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值