当前位置: 首页 > article >正文

Kadane 算法 二维 详解

Kadane 算法扩展到二维问题

二维 Kadane 算法用于解决矩阵中的 最大子矩阵和问题,即从给定矩阵中找出一个矩形区域,使得其所有元素的和最大。


问题描述

给定一个二维矩阵 matrix,其中包含正数、负数和零,找出一个矩形区域,使其所有元素的和最大,并返回最大和。

例如:

输入:
matrix = [
    [1,  2, -1, -4, -20],
    [-8, -3, 4,  2,   1],
    [3,   8, 10, 1,   3],
    [-4, -1, 1,  7,  -6]
]

输出: 29
解释: 最大子矩阵是 [[3, 8, 10], [-4, -1, 1]],和为 29。

Kadane 算法在二维中的扩展思路

1. 固定行边界

通过枚举上下边界,将二维问题转换为一维问题:

  • 将矩阵的某个子矩阵压缩为一维数组。
  • 压缩方式:对矩阵的列按行区间求和。
2. 使用一维 Kadane 算法

对每列的累积和进行处理,利用一维 Kadane 算法找到最大子数组和,从而求解当前行区间的最大子矩阵和。


算法步骤

  1. 初始化变量:

    • maxSum:存储全局最大子矩阵和。
    • leftright:记录矩阵左右边界。
    • topbottom:记录矩阵上下边界。
  2. 固定矩阵的左右边界:

    • 枚举左边界 left 和右边界 right
    • 压缩列到一维数组 temp,使 temp[i] 表示行 ileftright 列之间的累积和。
  3. 使用 Kadane 算法计算 temp 的最大子数组和,同时记录上下边界 topbottom

  4. 更新全局最大值 maxSum 和对应的边界。

  5. 返回最大子矩阵和。


代码实现

public class MaxSumRectangle {
    public static int maxSumRectangle(int[][] matrix) {
        int rows = matrix.length;
        int cols = matrix[0].length;

        int maxSum = Integer.MIN_VALUE;
        int left = 0, right = 0, top = 0, bottom = 0;

        // 固定左右边界
        for (int l = 0; l < cols; l++) {
            // 初始化列的累积和数组
            int[] temp = new int[rows];

            for (int r = l; r < cols; r++) {
                // 更新列的累积和
                for (int i = 0; i < rows; i++) {
                    temp[i] += matrix[i][r];
                }

                // 使用 Kadane 算法计算一维数组的最大子数组和
                int[] kadaneResult = kadane(temp);
                int currentSum = kadaneResult[0];
                int start = kadaneResult[1];
                int end = kadaneResult[2];

                // 更新全局最大值
                if (currentSum > maxSum) {
                    maxSum = currentSum;
                    left = l;
                    right = r;
                    top = start;
                    bottom = end;
                }
            }
        }

        // 打印最大子矩阵边界
        System.out.println("Top: " + top + ", Bottom: " + bottom);
        System.out.println("Left: " + left + ", Right: " + right);

        return maxSum;
    }

    // 一维 Kadane 算法,返回最大和及其起始和结束索引
    private static int[] kadane(int[] nums) {
        int maxSum = nums[0], currentSum = nums[0];
        int start = 0, end = 0, tempStart = 0;

        for (int i = 1; i < nums.length; i++) {
            if (currentSum + nums[i] > nums[i]) {
                currentSum += nums[i];
            } else {
                currentSum = nums[i];
                tempStart = i;
            }

            if (currentSum > maxSum) {
                maxSum = currentSum;
                start = tempStart;
                end = i;
            }
        }

        return new int[]{maxSum, start, end};
    }

    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, -1, -4, -20},
            {-8, -3, 4, 2, 1},
            {3, 8, 10, 1, 3},
            {-4, -1, 1, 7, -6}
        };

        System.out.println("最大子矩阵和为: " + maxSumRectangle(matrix)); // 输出: 29
    }
}

代码运行详解

输入矩阵:

[
    [1,  2, -1, -4, -20],
    [-8, -3, 4,  2,   1],
    [3,   8, 10, 1,   3],
    [-4, -1, 1,  7,  -6]
]
步骤 1:固定左右边界
  • 左边界 l = 0,右边界 r = 0

    • 列累积和 temp = [1, -8, 3, -4]
    • 使用 Kadane 算法找到最大子数组和为 3,对应上下边界 [2, 2]
  • 左边界 l = 0,右边界 r = 1

    • 列累积和 temp = [3, -11, 11, -5]
    • 最大子数组和为 11,对应上下边界 [2, 2]
  • 左边界 l = 1,右边界 r = 3

    • 列累积和 temp = [1, 3, 15, 4]
    • 最大子数组和为 29,对应上下边界 [1, 2]
步骤 2:更新最大值

全局最大值为 29,对应的矩形区域:

[
    [4, 2, 1],
    [8, 10, 1]
]

算法复杂度

时间复杂度
  • 外层两个循环:枚举左右边界,复杂度为 O ( n 2 ) O(n^2) O(n2)
  • 内层 Kadane 算法:复杂度为 O ( m ) O(m) O(m)

总时间复杂度为:
O ( n 2 ⋅ m ) O(n^2 \cdot m) O(n2m)
其中, n n n 是列数, m m m 是行数。

空间复杂度
  • 存储列累积和 temp,空间复杂度为 O ( m ) O(m) O(m)

总结

  1. 算法思想

    • 固定矩阵左右边界,将二维问题压缩为一维问题。
    • 使用 Kadane 算法求解一维问题,记录最大值和边界。
  2. 适用场景

    • 求解二维矩阵中的最大子矩阵和。
    • 在数据分析、图像处理等领域广泛应用。
  3. 优化方向

    • 若矩阵稀疏,可优化累积和的计算。
    • 特殊场景下可通过分治等方法进一步优化。

Kadane 算法的二维扩展不仅高效,还能很好地结合实际问题,是解决矩阵问题的重要工具之一。


http://www.kler.cn/a/404842.html

相关文章:

  • Linux(命令行扩展+命令行历史 大白话+图片)
  • 合法三元数量计算
  • 【加入默语老师的私域】C#面试题
  • Elasticsearch-Elasticsearch-Rest-Client(三)
  • ant-design-vue中table组件多列排序
  • C语言Day 04 学习总结
  • 如何创建一个网站?初学者的分步指南
  • 【Apache Paimon】-- 5 -- Flink 向 Paimon 表写入数据
  • 网络编程day2.2~day3——TCP并发服务器
  • TCP Listen 队列详解与优化指南
  • springboot基于大数据技术的电影推荐系统的设计与实现
  • 区块链预言机;预言机的部署、与智能合约的关系以及是否分布式;基于Fabric联盟链与链外世界的数据交互
  • Python 之网络爬虫
  • Spring Security SecurityContextHolder(安全上下文信息)
  • webpack进阶(二)
  • vue不刷新浏览器更新页面的方法
  • MacOS下的Opencv3.4.16的编译
  • pcap_set_buffer_size()函数
  • 使用Java爬虫时,有哪些性能优化技巧?
  • 解决MindSpore-2.4-GPU版本的安装问题
  • VSCode 2022 离线安装插件QT VSTOOl报错此扩展不能安装在任何当前安装的产品上。
  • C++ list (链表)容器
  • Spring validation 分组校验用法
  • WPF如何全局应用黑白主题效果
  • Java多线程编程详解
  • 亿咖通科技应邀出席微软汽车行业智享会,分享ECARX AutoGPT全新实践