一个矩阵的所有子矩阵最大和问题

Preface

??今天早上刷微博,看到LeetCode中国微博发了这样一条状态:

??已经好久没做题练练手了,于是想试试。LeetCode上,该题目的地址为:https://leetcode.com/problems/max-sum-of-sub-matrix-no-larger-than-k/

Analysis

??想了一上午,也没想出什么头绪。后来我看 LeetCode 上有不少人已经做出提交了。并且,在discuss页面里,有人公布了详细的解释与代码。

??我看了一下,他这个解法是基于Kadane Algorithm了。于是,先得学习一下什么是Kadane Algorithm

Kadane Algorithm

??Kadane Algorithm 用于解决对一列数组中,求其中子序列的和最大的值。Kadane 的代码很多,各种语言的也都有,我下面摘取这个网站上的C++代码,理解分析一下:

#include <iostream>
#include <climits>
using namespace std;

#define MAX(X, Y) (X > Y) ? X : Y
#define POS(X) (X > 0) ? X : 0

int kadane(int* row, int len)
{
    int x;

    //拿数组的第一个元素出来,若其大于0,则另sum = row[0]
    //若其小于或等于0,则令sum = 0,
    int sum = POS(row[0]);
    int maxSum = INT_MIN; //INT_MIN是<climits>文件定义的,代表int类型最小值:-2147483648
    for (x = 0; x < len; ++x)
    {
        //Kadane 算法的核心部分
        //maxSum用于记录最大的子序列和,并每一次与sum进行比较,若当sum比之前的maxSum要大,则将现在的sum值赋予maxSum
        //sum每加一个值,跟0进行一次比较,若加完row[x]都小于0了,那么就直接将sum置为0,接着开始一个新的子序列,并进行求和
        maxSum = MAX(sum, maxSum);
        sum = POS(sum + row[x]);
    }
    return maxSum;
}

int main()
{
    int N;
    cout << "Enter the array length: ";
    cin >> N;
    int arr[N];
    cout << "Enter the array: ";
    for (int i = 0; i < N; i++)
    {
        cin >> arr[i];
    }
    cout << "The Max Sum is: "<<kadane(arr, N) << endl;
    return 0;
}

2D Kadane Algorithm

??由于我们这一题是二维矩阵,并不是一维数组。因此,要将 kadane 算法扩展到2维上。同样作者也推荐了一个视频,是位印度哥们,讲解的非常好。视频在 YouTube 上,地址:https://www.youtube.com/watch?v=yCQN096CwWM,保证听几遍就懂。

??下面我就他讲解的,用 Excel 表格展示这个二维 kadane 算法的过程。

??如图下面所示的矩阵,黄色黄色部分,4×5 的大小。先定义几个变量:

??1. 变量 L : 代表遍历时,当前子矩阵的左边位置;

??2. 变量 R : 代表遍历时,当前子矩阵的右边位置;

??3. 右边浅绿色,与矩阵的 row数 相同的临时存储区,是将当前的 L 列、L+1 列、……、R?1 列、R 列,进行列相加,然后再用 kadane 算法判断相加得到的列数组(此时即为一维数组了,可以用一般意义上的 kadane 算法),求此时元素连续和最大的子数组,并与之前的最大值进行比较(这一点会在下面的过程中体现出来);

??4. 变量 currentSum : 当前 L、R 组成的子矩阵(注意:这个子矩阵的“行数量“与原来大矩阵相同),其中这个矩阵的子矩阵,产生的最大的和;

??5. 变量 maxSum : 纪录目前遍历下来的最大的子矩阵和;

??6. 变量 maxLeft : 纪录目前遍历下来的最大子矩阵的左边位置;

??7. 变量 maxRight : 纪录目前遍历下来的最大子矩阵的右边位置;

??8. 变量 maxUp : 纪录目前遍历下来的最大子矩阵的上面位置;

??9. 变量 maxDown : 纪录目前遍历下来的最大子矩阵的下面位置;

??注意:如果 currentSum 不大于 maxSum,则保持 maxSum、maxLeft、maxRight、maxUp、maxDown 这几个变量值不变。

??第一次遍历,L、R 都在矩阵的开始 0 处:

??第二次遍历, 此时将 R 向右移动一个位置到 1 处,保持 L 位置不变。将 L、R 两行之间的矩阵进行列相加,得到 3 6 0 0,求这个 3 6 0 0 序列的和最大子序列。

??很容易看出,最大值为9,所以 currentSum 为9,那么发现9比之前的 maxSum=4 要大,所以,此时将 9 给 maxSum=9。maxLeft=0 纪录此时的 L=0,maxRight=1 纪录此时的 R=1,maxUp 纪录此时最大子序列的上面开始位置:maxUp=0,maxDown 纪录此时最大子序列的下面结束位置:maxDown=1:

??第三次遍历:

??第四次遍历:

??第五次遍历:

??第六次遍历:

??第七次遍历:

??第八次遍历:

??第九次遍历:

??第十次遍历:

??第十一次遍历:

??第十二次遍历:

??第十三次遍历:

??第十四次遍历:

??第十五次遍历:

??经过十五次的遍历后,我们终于找到了这个矩阵,就是上图中红色区域部分。这个大矩阵(4×5) 的最大元素和为18。

??这就是2D kadane算法的过程。这个算法的空间复杂度为: O(row),时间复杂度为:O(column×column×row)

Find the max sum no more than K

??解决了如何寻找子矩阵的最大和问题,现在题目中还有一个限制。就是这个和不能大于给定的 K,这个作者也推荐了Quora上的一个帖子:Given an array of integers A and an integer k, find a subarray that contains the largest sum, subject to a constraint that the sum is less than k?。回答这个问题的人也是一位大神。

时间: 2024-10-24 05:28:18

一个矩阵的所有子矩阵最大和问题的相关文章

Task 4.2 求一个矩阵的最大子矩阵的和

任务:输入一个二维整形数组,数组里有正数也有负数.二维数组中连续的一个子矩阵组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). (1)设计思想:把二维矩阵分解成行.列的情况,可以相应把问题简化.之后分别依照行和列的基准来求每一个矩阵的和,再依次进行比较每个矩阵的和.最容易想到也是最容易实现的方法.遍历矩阵(行迭代器为i,列迭代器为j),以当前遍历到的元素为首a[i,j],计算二维子矩阵的和(sum=a[i,j]+a[i+1,j]+a[i,j+1]+a[i+

nyoj 104——最大和——————【子矩阵最大和】

最大和 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵. 例子:0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 其最大子矩阵为: 9 2 -4 1 -1 8 其元素总和为15. 输入 第一行输入一个整数n(0<n<=100),表示有n组测试数据:每组测试数据:第一行有两个的整数r,c(0<r,c&l

求一个矩阵中最大的2*2矩阵(元素和最大)的和

编程题在线编程题30分2/2最大子矩阵Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Problem Description:求一个矩阵中最大的2*2矩阵(元素和最大)的和.如:1 2 0 3 42 3 4 5 11 1 5 3 0中最大的是:4 55 3和为17输入m*n的矩阵输出该m*n矩阵的最大2*2子矩阵(元素和最大)的和 样例输入 1 2 0 3 4 ; 2 3 4 5 1 

结对开发——求二维环形数组所有子矩阵最大和的问题

一.题目要求: 输入一个二维整形数组,数组里有正数也有负数. 二维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 要求时间复杂度为O(n)题目:返回一个二维整数数组中最大子数组的和. 二.解决思路: 由于上次我们做过求二维数组最大子矩阵和的问题,又做了求一维环状数组的子数组最大值问题,这次就在以前的基础上进行修改,先对二维数组进行了重构,形成一个环状二维数组,然后再用求二维数组子矩阵最大和的方法求得最终结果.

IT公司100题-35- 求一个矩阵中最大的二维矩阵(元素和最大)

问题描述: 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 中最大的是: 4 5 9 10 分析: 2*2子数组的最大和.遍历求和,时间复杂度为O(mn). 代码实现: 1 // 35.cc 2 #include <iostream> 3 #include <climits> 4 using namespace std; 5 6 int find_max(int (*a)[5], int m, int n) { 7 in

顺时针输出一个矩阵

题目:顺时针输出一个矩阵(N*N). 假设一个矩阵为: 1   2   3   4 5   6   7   8 9  10 11 12 13 14 15 16 那么程序应该给出的输出为:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 这个问题在网上也搜集了一下答案,没有什么巧妙的办法,所以下面给出的是完全按照顺时针走向输出的一个代码(自己亲手编写,测试通过): #include <stdio.h> #define N 5 //矩阵的维度 void clockwis

matlab中如何求某一个矩阵的标准差和均值

方法: 先reshape成行向量或者列向量 然后,利用mean函数,std函数. 构造测试数据,可以利用random函数,就好.利用这个函数,可以构造不同分布的随机数列(或 矩阵). 如: >> y =random('norm',2,0.3,3,4) y = 2.1391 2.2945 2.0769 2.1751 1.9334 1.6805 1.9315 1.8912 1.8775 1.8126 1.9733 1.7686 >> rows = reshape(y,3*4,1) ro

【编程题目】求一个矩阵中最大的二维矩阵(元素和最大)

35.(矩阵)求一个矩阵中最大的二维矩阵(元素和最大).如:1 2 0 3 42 3 4 5 11 1 5 3 0中最大的是:4 55 3要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 早上灭小题! /* 35.(矩阵) 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 0 3 4 2 3 4 5 1 1 1 5 3 0 中最大的是: 4 5 5 3 要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 */ #include <stdio.h>

矩阵下标与子矩阵的提取

对于某一个矩阵A有以下的规定: A(m,n)提取矩阵的m行和n列: A(:,n)提取矩阵的n列: A(m,:)提取矩阵的m行: $A(m_1:m_2,n_1:n_2)$提取矩阵$m_1$到$m_2$行,$n_1$到$n_2$列的所有的元素(子块): A(m:end,n)提取矩阵的m行到最后一行和第n列的子块: A(:)得到一个长列的矩阵.