3

我认为是 O(3^n),有什么想法吗?此方法查找给定数字是否是给定集合的任何子集的总和(overloads boolean isSumOf(int[]s,int n))。如果目标等于 0 或消耗集合中的当前数字(或不消耗)并再次尝试,则该方法在每个递归调用中进行检查,而 target>0 并且我们还没有耗尽数组。

    * @param set a given set of natural numbers.
    * @param target the number. 
    * @param i where we are in the set.
    * @return true if we reached target, else returns false.
    **/
   private static boolean isSumOf(int[] set,int target,int i)
   {

        // Found the set if we are now at 0.
        boolean isSum = (target==0);
        // Look no further if no more to try.
        if ( target > 0 ) 
        {
            // Look no further if we've exhausted the array.
            if ( i < set.length )
            {
                // Try or consume this number in the set (or not) and try again.
                isSum = isSumOf(set, target - set[i], i)  // Consume the current number in the set and try again recursively. 
                    || isSumOf(set, target - set[i], i+1) // Consume the current number in the set and avdance to rhe next number.
                    || isSumOf(set, target, i+1); // Try the current number and avance to the next number in the set.
            }

        }

        return isSum;
4

3 回答 3

3

你的问题是NP完全的。这些都是坏消息。

好消息是这是一个众所周知的 NP 完全问题!耶!

http://en.wikipedia.org/wiki/Subset_sum

就像评论中所说的那样,您的算法可以无限期地运行,即使输入大小适中,也会运行很长时间。

如果您对该代码在中等大小的输入中运行有任何希望,您需要重新考虑您的方法。

您的方法中的一个大问题是您正在计算许多重复的子问题。想想通常的朴素斐波那契递归实现。

从好的方面来说,您的子问题具有相当优化的结构,这很好地表明您的问题将成为动态编程方法的绝佳候选者。它使事情变得更容易,您甚至不需要总结为该值的确切数字,只需一个布尔输出。

我链接的维基百科文章讨论了一些伪多项式方法以及通过动态编程的多项式方法。

于 2012-12-28T12:56:28.383 回答
1

它看起来比O(3^n)因为第一个递归调用isSumOf(set, target - set[i], i)将调用自身而不提前i,这对于大型目标将导致大量的每个分支的分支i

像这样的方法可以从记忆化中受益,以降低其复杂性。

于 2012-12-28T12:58:24.657 回答
1

让我们假设 set 只包含大于 0 的数字。另外请注意,isSumOf(set, target - set[i], i+1)可以省略第二个递归调用而不改变结果。相当于先减去 set[i](第一次递归调用),然后推进 i(第三次递归调用)。我正在讨论这个简化版本。

如果 n 是目标并且 k 是集合的大小,我认为复杂度是 O(n^k) 但我没有完整的证明。假设我们正在枚举所有可能性,并且在找到分区时不会停止(真正的算法确实会因为快捷方式或 || 而停止)。最坏的情况似乎是集合中的所有元素都是 1。所以我们必须提前 ik 次才能到达递归的末尾,并且对于每一步提前 i 有少于 n 个可能性。

于 2012-12-28T13:15:54.367 回答