【问题标题】:Partition algorithm without loop, only recursion没有循环的分区算法,只有递归
【发布时间】:2017-10-11 02:06:34
【问题描述】:

给定一个整数列表。找出它是否可以分成两个总和相等的子列表。列表中的数字未排序。

例如:
像 [1, 2, 3, 4, 6] 这样的列表将返回 true,因为 2 + 6 = 1 + 3 + 4 = 8
像 [2, 1, 8, 3] 这样的列表将返回 false。

我在一个在线练习平台上看到了这个问题。我知道如何使用 for 循环 + 递归来解决它,但是如何在没有循环(或迭代器)的情况下解决它?

【问题讨论】:

    标签: algorithm recursion partitioning depth-first-search partition-problem


    【解决方案1】:

    思考这个问题的方式尝试思考你可以通过哪些方式将这个问题分解为相互依赖的较小问题。首先想到的是根据索引来拆分问题。让我们尝试从左到右(每次调用将索引增加 1)。我们的基本情况是在我们遍历所有元素之后,即数组的末尾。我们需要在那里做什么?相互比较总和,所以我们需要通过这些总和。对于实际的递归调用,有两种可能性,即添加到任一总和的当前元素。我们只需要检查这两个调用,如果有一个返回true,则返回true


    这会导致解决方案没有任何循环,方法是让您的递归函数将当前索引以及两个总和作为参数,并有两种递归情况 - 一种是将当前元素添加到一个总和,以及一个将其添加到另一个总和的位置。然后在到达数组末尾时比较总和。

    在 Java 中,它看起来像这样:

    boolean canBeDividedEqually(int[] array)
    {
        return canBeDividedEquallyHelper(array, 0, 0, 0);
    }
    
    boolean canBeDividedEquallyHelper(int[] array, int i, int sum1, int sum2)
    {
        if (i == array.length)
            return sum1 == sum2;
        return canBeDividedEquallyHelper(array, i+1, sum1 + array[i], sum2) ||
               canBeDividedEquallyHelper(array, i+1, sum1, sum2 + array[i]);
    }
    

    这可以通过只传递 1 个和并从中添加或减去,然后在最后与 0 进行比较来稍微改进。

    请注意,这是the partition problem,这种蛮力解决方案需要指数级时间(即,随着输入大小的增加,它会变得非常缓慢)。

    【讨论】:

    • 如果我们将memoization添加到这个函数中,递归将花费伪多项式时间。
    • 谢谢!完美运行!
    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-30
    • 2010-10-21
    • 1970-01-01
    • 2015-06-09
    • 2012-10-24
    相关资源
    最近更新 更多