如何在O(n)中获得2D数组中的最大总和?

时间:2015-01-02 21:20:31

标签: java arrays algorithm multidimensional-array

我需要计算2D数组中可能的最大总和,但代码必须是O(n)的效率。 n是数组中的数字。

阵列就像楼梯,用户只需要输入N个数字。我们不需要检查它是否是有效号码。

数字将以如下数组显示:

1

2 3

4 5 6

7 8 9 10

每一行还有一个号码。

您需要从第一行或最后一行开始获得最大的总和路径。 在每次迭代中,您只能向下移动一步,或者向下,向左/向右和向右移动一步。

这意味着如果你从第一行开始,你可以去2或3.让我们说你选择2;现在你只能去4或5.如果你选择5,你可以只去7或8或9.或者如果你想你可以去1> 3> 6>但你不能去1> 2> 6> 10因为2与6没有连接。

您也可以连续选择一个数字。你不能去1> 2> 3> 6> 8> 9> 10或类似的东西。

我们也可以更改单元格的值,但路径必须相同。这意味着我可以将9更改为50,但它不会很好,因为它不是原始数组中的好路径。 (该阵列1中的最大总和路径> 3> 6> 10,所以我不能去不同的小区)

我的问题是我需要这个代码以O(n)的效率运行。

我试着从最后一行开始,检查它可以走的每一条有效路径,我试图在各种可能性的最大数量。第一个不是O(n)效率,第二个可以得到错误答案。

我也尝试从第一行开始,扫描并比较所有步骤,但同样不是O(n)效率。

为了确保,我并没有要求任何人为我编写代码,只是为了帮助我找出计算它的最佳方法。

BTW,看到了一些评论,并希望在最后添加,我需要打印最大路径总和,而不是路径本身。

2 个答案:

答案 0 :(得分:4)

您可以自下而上确定最大总和。例如,两个底行是:

  4   5   6
 / \ / \ / \
7   8   9  10

现在累积最大可能总和到第二行但最后一行:

 12  14  16
 / \ / \ / \
7   8   9  10

例如,你可以从节点4的7或8中获得的最大值是12.继续这个,但是使用max-sum值,到顶部:

     20
     / \
   16  19
   / \ / \
 12  14  16
 / \ / \ / \
7   8   9  10

顶级节点现在具有最大可能总和:1 + 3 + 6 + 10 == 20.这种方法会破坏原始数据(因为它用max-sums覆盖它)并且它不会给你路径,只有最大金额的值。

这里,三角形数组看起来像一棵树,但你并没有真正构建一棵树:链接很容易用它们的位置来描述。

编辑:我现在意识到这并没有完全解决你的问题,因为它省略了左边可能的步骤,但原则仍然是好的:积累最大可能的子从下到上加上总和,除了你需要考虑下面的三个值,而不仅仅是两个。 (我有点不喜欢重绘ASCII树。: - )

编辑II :正如@rpattiso指出的那样,您可以通过跟随顶部三个可能子节点的最大总和来获得累积树中的最佳路径。

编辑III :当您将矩阵视为楼梯并考虑每个节点的三个子节点时,图表将变为:

  20
   | \
  16  19
   | X | \
  12  14  16
   | X | X | \
   7   8   9  10

这里,X表示两条交叉路径。请注意,第一列是一种特殊情况,因为此列中的节点只有两个子节点。

如果m是行数,n = m*(m + 1)/2是单元格数,如果您的数组由二维C风格数组a[row][col]表示,那么您的最大值和算法是:

int row = m - 1;

while (row--) {        
    a[row][0] += max(a[row + 1][0], a[row + 1][1]);

    for (int col = 1; col < row + 1; col++) {
        int a1 = a[row + 1][col - 1];
        int a2 = a[row + 1][col];
        int a3 = a[row + 1][col + 1];

        a[row][col] += max(a1, a2, a3);
    }
}

您的最大总和是a[0][0]的值。

答案 1 :(得分:0)

一个选项是通过放置相关边,添加汇聚节点并从1运行Dijkstra到汇聚节点来准备有向图。虽然不是线性的(汇节点是连接到7 8 9 10的节点) 另一个解决方案可能是动态编程,自下而上(在第一个答案中描述)或自上而下