算法问题拓展——kadane算法及其二维数组的扩展
Posted limitcm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法问题拓展——kadane算法及其二维数组的扩展相关的知识,希望对你有一定的参考价值。
上次完成最大子序和算是对这类算法的入门,现在想要对其进行加深学习。
最大子数组的问题里对我印象最深的就是动态规划的解决方法——“解其不同部分(即子问题),再根据子问题的解以得出原问题的”。这种解决方法十分常用,而其在一维数组中的总结以及最优解就是Kadane算法。
Kadane算法
//C++伪代码
int kadane(){ int ans = n[0]; dp[0] = n[0]; for(int i = 1;i < strlen(n);i++){ dp[i] = Max(n[i],dp[i-1]+n[i]); ans = Max(dp[i],ans); } }
作为最简洁的算法,我在这里先列上,java形式在之前的随笔中就有,但发现解释和我的理解有不一样的地方,这影响到我对二维数组的理解,所以在此重新学习一遍。
首先是关注点。要着重注意:指定数组中某一个元素 n[i] 作为最大子序列的末尾元素时, 能找到的最大子数组的求和值是多少。这样但我们看第一个元素n[0]的时候,只需要关注其后一个元素即可;而在算子序和的时候,n[i...j]也只需要关注n[j+1]即可。意思就是n[i...j]中的最大子数组只会包含或不包含n[j+1]。如果包含,再看下一个元素。如果不包含,那么从n[j+2]再开始找即可。过程中记录出现的最大子序和。
二维数组中用动态规划
既然问题扩展了一个维度,那就只要找到子问题就还是能用动态规划。
如果简单的说:将同一列的元素与前一行的元素相加得到一个一维数组,对一维数组进行Kadane算法就能找出最大子数组的和。但这样只是描述了过程,很难理解(不过对过程进行一次演绎后确实能理解不少,It just work)。
public int kadane2d(int n[][]){ int rows = n.length; int cols = n[0].length; int temp[] = new int[rows]; int result;//maxSum for(int left = 0; left < cols ; left++){ for(int i=0; i < rows; i++){ temp[i] = 0; } for(int right = left; right < cols; right++){ for(int i=0; i < rows; i++){ temp[i] += n[i][right]; } int kadaneResult = kadane(temp);//currentSum if(kadaneResult > result){ result = kadaneResult; } } } return result; }
时间复杂度近似O(n3)——O(cols*rows*cols)
具体过程为Maximum Sum Rectangular Submatrix in Matrix dynamic programming/2D kadane(Youtube)。
后记,记下自己的未实现过程。
本来想着用递归和二分法来解决并节约时间复杂度,但解决时遇到问题,没法在二分后判断跨越中间的子数组的大小,所以宣告放弃。但或许什么时候想出来了也不失为一种解决方案。
参考网上解题过程后,已经觉得找最大子数组问题是把我引入动态规划的一道经典例题,所以最后归纳的方案还是用了Kadane算法来解决。
以上是关于算法问题拓展——kadane算法及其二维数组的扩展的主要内容,如果未能解决你的问题,请参考以下文章
LeetCodeLeetCode之乘积为正数的最长子数组长度——暴力枚举+动态规划+Kadane算法