使用分而治之的最大子数组

Posted

技术标签:

【中文标题】使用分而治之的最大子数组【英文标题】:Maximum SubArray Using Divide and Conquer 【发布时间】:2017-01-12 16:39:16 【问题描述】:

我正在从“算法简介”一书中学习算法。我想实现一个分而治之的算法来找到一个数组的最大子数组。这是我的解决方案,但我得到了错误的结果。

任何帮助将不胜感激。请解释一下,因为我更感兴趣的是理解它而不是让它工作。谢谢。

def maxNumber(int a, int b)
return a > b ? a : b;


def maxNumber(List a, List b, List c)
return maxNumber(a.sum(), maxNumber(b.sum(), c.sum()))


//int sum(List list)
//    int sum = 0
//    list.each 
//        sum+= it
//    
//    sum
//

def maxCrossing(ArrayList<Integer> list, int low, int mid, int high)
int sum = 0
int leftSum = Integer.MIN_VALUE
int maxLeftIndex = -1

/*for (int i = low; i <= mid ; i++) 
    sum += list[i]
    if (sum > leftSum) 
        leftSum = sum
        maxLeftIndex = i
    

*/

for (int i = mid; i >= low ; i--) 
    sum += list[i]
    if (sum > leftSum) 
        leftSum = sum
        maxLeftIndex = i
    



sum = 0
int rightSum = Integer.MIN_VALUE
int maxRightIndex = -1

for (int i = mid + 1; i <= high ; i++) 
    sum += list[i]
    if (sum > rightSum) 
        rightSum = sum
        maxRightIndex = i
    



def returnList  = []
for (int i = maxLeftIndex; i < maxRightIndex + 1; i++) 
    returnList.add(list[i])

return returnList


def maxSubArray(ArrayList<Integer> list,int low, int high)
if (low == high) return [list[low]]

int mid = (low + high) / 2

def leftResults = maxSubArray(list, low, mid)
def rightResults = maxSubArray(list, mid + 1, high)
def crossResults = maxCrossing(list, low, mid, high)

/*if (rightResults[2] > leftResults[2] && rightResults[2] > crossResults[2]) return rightResults
if (leftResults[2] > rightResults[2] && leftResults[2] > crossResults[2]) return leftResults
else return crossResults*/


maxNumber(leftResults, rightResults, crossResults)


//Testing Features 
println("Enter array members")
ArrayList<Integer> myList =  [-2, -5, 10, -2, -3, 1, 5, -6]  //System.in.newReader().readLines()
int size = myList.size()
def maxSum = maxSubArray(myList, 0, size - 1)
println("Maximum sub-array is: " + maxSum)

【问题讨论】:

您是否尝试过笔和纸示例并调试过您的代码是否与您在纸上的相同? 我在用一本书,书中列出了这个算法。另外,我在其他地方搜索并找到了相同的算法。我不明白的是递归部分。我认为这就是问题所在。我需要一些进一步的解释。我感到困惑的地方......我已经学习了递归并得到了它的例子。但无法弄清楚它是如何在这里使用的。 如果您有更好的建议,请详细说明。我想了解它。我之前尝试过合并排序,但根本无法让它工作。 Kadane 的算法适用于此...为什么要使用分而治之的方式使事情复杂化? 谢谢@User_Targaryen 我已经看到了那个算法。正如我所说,不是让它发挥作用。我想了解分治算法。我尝试用分而治之的合并排序,我失败了,这个也失败了。它在我的教学大纲中。我必须理解它 【参考方案1】:

认为您的主要问题之一是在 maxCrossing 中的 if 语句周围缺少大括号

所以:

if (sum > leftSum) leftSum = sum
maxLeftIndex = i

应该是:

if (sum > leftSum) 
    leftSum = sum
    maxLeftIndex = i

另外,我相信在检查十字路口的下部时,你需要从中点开始向下工作(这里可能是错误的)

此外,传回索引和总和没有多大意义...我将其更改为仅返回每个步骤的最大数组(然后我们可以调用 sum() on)

这是(我认为)您的代码中的可行解决方案:

def maxResults(List a, List b, List c) 
    a.sum() > b.sum() && a.sum() > c.sum() ? a :
    b.sum() > c.sum() ? b :
    c


def maxCrossing(List list, int low, int mid, int high)
    int sum = 0
    int leftSum = Integer.MIN_VALUE
    int maxLeftIndex = -1

    for (int i = mid; i >= low; i--) 
        sum += list[i]
        if (sum > leftSum) 
            leftSum = sum
            maxLeftIndex = i
        
    

    sum = 0
    int rightSum = Integer.MIN_VALUE
    int maxRightIndex = -1

    for (int i = mid + 1; i <= high ; i++) 
        sum += list[i]
        if (sum > rightSum) 
            rightSum = sum
            maxRightIndex = i
        
    

    return list[maxLeftIndex..maxRightIndex]


def maxSubArray(List list, int low, int high)
    if (low == high) return [list[low]]

    int mid = (low + high) / 2

    def leftResults = maxSubArray(list, low, mid)
    def rightResults = maxSubArray(list, mid + 1, high)
    def crossResults = maxCrossing(list, low, mid, high)

    maxResults(rightResults, leftResults, crossResults)


//Testing Features
println("Enter array members")
ArrayList<Integer> myList =  [-2, -5, 10, -2, -3, 1, 5, -6]   //System.in.newReader().readLines()
int size = myList.size()
def maxSum = maxSubArray(myList, 0, size - 1)
println("Maximum sub-array is: " + maxSum)

顺便说一句,这个输出是:

Maximum sub-array is: [10, -2, -3, 1, 5]

【讨论】:

我不知道你的解决方案是如何工作的,但是 leftResults 和 rightResults 是整数,你将它们传递给一个列表,我的编译器在抱怨。谢谢 Possible solutions: maxNumber(int, int), maxNumber(java.util.List, java.util.List, java.util.List) groovy.lang.MissingMethodException: No signature of method: MaxSubArray.maxNumber() is applicable for argument types: (java.lang.Integer, java.lang.Integer, java.util.ArrayList) values: [-2, 10, [-6, -2, -5, 10]] Possible solutions: maxNumber(int, int), maxNumber(java.util.List, java.util.List, java.util.List) at MaxSubArray$maxNumber$1.callCurrent(Unknown Source) at MaxSubArray.maxSubArray(MaxSubArray.groovy:74) 同上ArrayList&lt;Integer&gt; myList = [-2, -5, 10, -2, -3, 1, 5, -6] 我已使用新解决方案编辑了我的答案,并纳入了您的建议。 你使用的是什么版本的 Groovy?

以上是关于使用分而治之的最大子数组的主要内容,如果未能解决你的问题,请参考以下文章

最大子数组:分而治之

如何使用分而治之的方法解决“固定大小的最大子数组”?

用于查找最大子数组的分而治之算法 - 如何同时提供结果子数组索引?

运行分而治之算法后从数组中打印最大子数组值

使用分而治之的最大子阵列产品有人吗?

最大子数组的特殊情况