算法问题拓展——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算法来解决。

posted @ 2019-03-23 12:07  limitCM  阅读(511)  评论(0编辑  收藏  举报