硬币算法的复杂性

时间:2014-12-31 02:20:45

标签: java algorithm big-o complexity-theory

有人能告诉我这段代码的复杂性(Big O符号首选)吗?它找到了最少数量的"硬币"需要制定目标总和。 为此,它计算从1开始的每个数字的最小硬币数量。每个数字根据可能的总和数量来计算,并使用成本最小的数字。一个例子希望能让这个更清晰

如果"硬币"是{1,3,4},目标是13然后它从1到13迭代,其中2的成本最小为(0 + 2,1 + 1),c(5)是最小的成本( c(0)+ c(5),c(1)+ c(4),c(2)+ c(3))等,直至c(13)

这是背包问题的一个版本,我想知道如何定义其复杂性?

代码:

import java.util.*;

public class coinSumMinimalistic {
    public static final int TARGET = 12003;
    public static int[] validCoins = {1, 3, 5, 6, 7, 10, 12};

    public static void main(String[] args) {
        Arrays.sort(validCoins);

        sack();
    }

    public static void sack() {
        Map<Integer, Integer> coins = new TreeMap<Integer, Integer>();
        coins.put(0, 0);
        int a = 0;
        for(int i = 1; i <= TARGET; i++) {
            if(a < validCoins.length && i == validCoins[a]) {
                coins.put(i, 1);
                a++;
            } else coins.put(i, -1);
        }
        for(int x = 2; x <= TARGET; x++) {
            if(x % 5000 == 0) System.out.println("AT: " + x);
            ArrayList<Integer> list = new ArrayList<Integer>();
            for(int i = 0; i <= x / 2; i++) {
                int j = x - i;
                list.add(i);
                list.add(j);
            }
            coins.put(x, min(list, coins));
        }
        System.out.println("It takes " + coins.get(TARGET) + " coins to reach the target of " + TARGET);
    }

    public static int min(ArrayList<Integer> combos, Map<Integer, Integer> coins) {
        int min = Integer.MAX_VALUE;
        int total = 0;
        for(int i = 0; i < combos.size() - 1; i += 2) {
            int x = coins.get(combos.get(i));
            int y = coins.get(combos.get(i + 1));
            if(x < 0 || y < 0) continue;
            else {
                total = x + y;
                if(total > 0 && total < min) {
                    min = total;
                }
            }
        }
        int t = (min == Integer.MAX_VALUE || min < 0) ? -1:min;
        return t;
    }
}
编辑:经过研究,我认为复杂度为O(k * n ^ 2),其中n是目标,k是提供的硬币数量,这是正确的吗?

1 个答案:

答案 0 :(得分:5)

我认为你提供的代码有点混乱。所以这篇文章更多的是关于概念算法而不是真实算法。这可能有点不同,因为例如ArrayList<T>中的插入不是 O(1),但我确信您可以使用良好的数据结构(例如{{1} } s)为此让所有操作都在恒定的时间内运行。

您的算法基本上做的是:

  1. 首先是将所有给定硬币映射到一张的地图:它需要一枚硬币才能达到硬币的价值。
  2. 对于每次迭代,它将所有已实现的值与所有已实现的值混合。因此,结果是硬币的总和,它取硬币的数量的总和,除非它已经存在于集合中。
  3. 此步骤忘记:将值严格大于的值大于所请求的值:由于所有硬币都是严格正数,因此您永远无法使用此类值构建值组成小于要求的值。
  4. 构建所请求的硬币值之前,您一直这样做。
  5. 如果在迭代 i ,添加到集合中的所有值都严格大于,则可以停止:请求的值无法建造。
  6. 参数是:

    • n :硬币数量。
    • r :请求的值。

    第一个观察是(2.)的每个步骤需要 O(s ^ 2)时间, s 在开始时集合中的元素数量迭代:这是因为你将每个值与每个值匹配。

    第二个观察结果是,集合中的元素永远不会超过请求的值。这意味着 s O(r)的限制(我们假设所有硬币都是整数,因此该集合最多可包含从0到 r的所有整数值-1 的)。因此,步骤(2。)具有O(r ^ 2)的最大时间复杂度。

    此外,该集合逐步演变:在每次迭代中,您将始终构造一个 new 值,该值至少比目前的最大值大一个。因此,该算法将执行最大 O(r)迭代。

    这意味着该算法的时间复杂度为 O(r ^ 3) r O(r ^ 2)


    为什么行为是指数性的,因此至少是NP难?

    第一个论点是,它取决于你如何表示输入:在许多情况下,数字是使用 radix 大于或等于{的系统来表示的{1}}。这意味着对于 k 字符,您可以使用 g 基数来表示使用 O(g ^ k)进行缩放的值。因此呈指数级。换句话说,如果使用LinkedList<T>位数,最坏情况, r = O(2 ^ 32)。因此,如果您将此作为输入,则存在指数部分。如果您使用一元表示法对目标进行编码,则算法位于 P 中。但当然这有点像 padding-argument :假设你提供了足够无用的输入数据(指数甚至超指数),所有算法都在 P 中,但是你不会为此付出太多。

    第二个参数是,如果您将所请求的值保留在输入之外,则只能声明您以 n 币开头。您知道迭代次数是固定的:您将目标值视为未知常量。每次迭代,2潜在正方形中的值总数。因此,这意味着计算工作是:

    32

    很明显,这种行为在 n 中呈指数形式。