【问题标题】:Understanding Recursion / how are subproblems combined (Max-Subarray Algorithm)了解递归/子问题如何组合(最大子数组算法)
【发布时间】:2014-05-30 03:21:53
【问题描述】:

我在理解分而治之算法时遇到了一些问题。我已经读过,为了成功地应用递归,你需要有一个“递归的信念飞跃”,你不应该为每一步的细节而烦恼,但我并不满足于仅仅接受递归有效。条件都满足了,因为目前对我来说这似乎很神奇,我想了解它为什么会起作用。

所以我得到了以下在伪代码中找到最大子数组的递归算法:

Find-Maximum-Subarray(A, low, high)
if high == low
    return (low, high, A[low])
else
    mid = [(low + high)/2]
    (left-low, left-high, left-sum) = Find-Maximum-Subarray(A, low, mid)
    (right-low, right-high, right-sum) = Find-Maximum-Subarray(A,mid + 1, high)
    (cross-low, cross-high, cross-sum) = Find-Max-Crossing-Subarray(A,low, mid, high)
    if left-sum >= right-sum and left-sum >= cross-sum
        return (left-low, left-high, left-sum)
    else if right-sum >= left-sum and right-sum >= cross-sum
        return (right-low, right-high, right-sum)
    else
        return (cross-low, cross-high, cross-sum)

其中 Find-Max-Crossing-Subarray 算法由以下伪代码给出:

Find-Maximum-Crossing-Subarray(A, low, mid, high)
left-sum = -INF
sum = 0
for i = mid down to low
    sum = sum + A[i]
    if sum > left-sum
        left-sum = sum
        max-left = i
right-sum = -INF
sum = 0
for j = mid + 1 to high
    sum = sum + A[j]
    if sum > right-sum 
        right-sum = sum
        max-right = j
return (max-left, max-right, left-sum + right-sum)

现在,当我尝试将此算法应用于示例时,我很难理解所有步骤。

数组被“分解”(使用索引,而不实际更改数组本身)直到高等于低。我认为这对应于第一次调用,因此首先对数组左侧的所有项调用 Find-Maximum-Subarray,直到 high==low==1。然后 (low, high, A[low]) 返回,在这种情况下为 (1, 1, A[1])。现在我不明白这些值在调用的其余部分是如何处理的。

此外,我不明白该算法实际上是如何比较长度 > 1 的子数组的。有人可以向我解释一下,一旦函数的调用之一触底,该算法将如何继续吗?

【问题讨论】:

  • 我在另一个线程中的answer 可能会帮助你。它深入到一个好的递归示例中。

标签: algorithm recursion divide-and-conquer


【解决方案1】:

简而言之:
A 为长度为n 的数组。您想计算您调用Find-Maximum-Subarray(A, 0, n-1)A sou 的最大子数组。现在试着让问题变得更简单:

  1. 案例。高 = 低:
    在这种情况下,数组只有 1 个元素,因此解决方案很简单
  2. 高!=低
    在这种情况下,解决方案很难找到。所以尽量让问题变小。如果我们将数组A 分割成一半长度的数组B1B2 会发生什么。现在只有3个新病例

    a) A 的最大子数组也是B1 的子数组,但不是B2 的子数组
    b) A 的最大子数组也是B2 的子数组,但不是B1 的子数组
    c) A的最大子数组与B1B2重叠

    所以你分别计算B1B2 的最大子数组,并寻找一个重叠的解决方案,最后你取最大的一个。

现在的诀窍是,您可以使用 B1B2 完成相同的操作。

例子:

A =[-1, 2, -1, 1]
Call Find-Maximum-Subarray(A, 0, 3);
 - Call Find-Maximum-Subarray(A, 0, 1); -> returns ( 1, 1, 2 )  (cause 2 > 1 > -1,  see the subcalls)
    - Call Find-Maximum-Subarray(A, 0, 0); -> returns ( 0, 0, -1 )
    - Call Find-Maximum-Subarray(A, 1, 1); -> returns ( 1, 1, 2 )
    - Call Find-Max-Crossing-Subarray(A, 0, 0, 1); -> returns ( 0, 1, 1 )
 - Call Find-Maximum-Subarray(A, 2, 3); -> returns ( 3, 3, 1 ) ( 1 > 0 > -1, see subcalls)
    - Call Find-Maximum-Subarray(A, 2, 2); -> returns ( 2, 2, -1 )
    - Call Find-Maximum-Subarray(A, 3, 3); -> returns ( 3, 3, 1 )
    - Call Find-Max-Crossing-Subarray(A, 2, 2, 3); returns ( 2, 3, 0 )
 - Call Find-Max-Crossing-Subarray(A, 0, 1, 3); -> returns ( 1, 3, 2 )
    - Here you have to take at least the elements A[1] and A[2] with the sum of 1, 
      but if you also take A[3]=1 the sum will be 2. taking A[0] does not help 
      due to A[0] is negative
 - Now you have only to look which subarray has the larger sum. In this case you 
   have two with the same size: A[1] and A[1-3]. Return one of them.

【讨论】:

  • 我明白这一点。我不明白的是我们如何从基本情况的解决方案到长度为 2 的子数组的解决方案以及最终整个数组的解决方案。所以例如如果我调用 Find-Maximum-Subarray 我们最终将在递归触底时得到长度为 1 的子数组。现在该算法如何使用基本情况的结果?这对我来说似乎很神奇。计算机将这些基本案例结果存储在哪里?算法中的哪些函数调用了基本案例结果?
  • 我添加了一个长度为 4 的示例
  • 非常感谢,这正是我想知道的。你帮了我很多,我感谢你的努力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-01
  • 2021-06-14
  • 1970-01-01
  • 2021-11-09
  • 1970-01-01
  • 2012-08-11
  • 2014-08-29
相关资源
最近更新 更多