简体   繁体   中英

What is the time complexity of this dynamic programming algorithm?

I'm learning dynamic programming solutions from a book. I understand the solution to a question, but I'm not sure of the time complexity of the solution which, the book didn't provide.

My question:

Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5 cents), and pennies (1 cent), write code to calculate the number of ways of representing n cents.

My analysis:

Every input must go through 4 "levels", which is 25, 10, 5,1. In the first level the loop will execute n/25 time, in the second level the loop will execute at most (n/25) (n/10) times, the third executes at most (n/25) (n/10) (n/5), the last level executes at most(n/25) (n/10)*(n/5) n. So the total running time is (n/25) (n/10)*(n/5) n +(n/25) (n/10) (n/5)+(n/25) (n/10)+n/25 , which is O(N^4). First I'm not sure if my induction is right. Second, if I'm right, I wonder if there's a tighter bond since in each level I only calculated the max times instead of the average times.

The solution is below:

int makeChange(int n) {
    int[] denoms = {25, 10, 5, l};
    int[][] map = new int[n + l][denoms.length]; // precomputed 
            vals
    return makeChange(n, denoms, 0, map);
}

int makeChange(int amount, int[] denoms, int index, int[][] map) {
    if (map[amount][index] > 0) {//retrieve value
        return map[amount][index];
     }
    if (index >= denoms.length - 1) return 1; // one denom remaining
    int denomAmount denoms[index];
    int ways = 0;
    for (int i= 0; i * denomAmount <= amount; i++) {
        //go to next denom, assuming i coins of denomAmount
        int amountRemaining = amount - i * denomAmount;
        ways += makeChange(amountRemaining, denoms, index + 1, 
             map);
    }
    map[amount][index] = ways;
    return ways;
}

The algorithm as written is O(n 2 ). When you analyze recursive functions, you can separate them into two pieces:

  1. The work done by each function
  2. The amount of times that work is done

Then it's just a matter of multiplying those two numbers together. Because the function results are being cached here, the work for each value in the cache is going to be done at most once. Since the cache is O(n) in size, it takes O(n) time to fill.

For the work done in each function, there is a while loop that goes through O(n) iterations. Multiplying these together gives you an estimate of O(n 2 ), which is born out by doing a crude estimate (doubling the input value results in roughly quadrupling the time taken).

Just think recursively to compute the complexity. To do this, just consider the number of 25 coins and then for the others. If T(n,i) shows the number of ways to represent n with the last i number of denoms , the we will have T(n,4) = T(n-25, 3) + T(n - 2 * 25, 3) + ... + T(n - n//25 * 25, 3) ( n//25 means the integer division of n ). Now we can repeat this for 10 , 5 , and 1 respectively.

Therefore, to find a tight bound for the complexity, you can suppose n is divisible by 25 , 10 , and 5 many times to get the worst case and tight analysis.

Hence, the tight analysis is:

T(n,4) = sum_{i=1}^{n/25} T(n-i*25, 3)
T(n,3) = sum_{i=1}^{n/10} T(n-i*10, 2)
T(n,2) = sum_{i=1}^{n/5} T(n-i*5, 1)
T(n,1) = 1

Now, we can compute from bottom to top. T(n,2) = Theta(n/5) , T(n,3) = Theta(n/10 * n/5) , and T(n,4) = Theta(n/25 * n/10 * n/5) = Theta(n^3) . As you can see the final result is Theta(n^3) and the asymtotic analysis deos not depned on the exact value of n or that is divisible by 5 , 10 , or 25 .

Also, you have a mistake in your computation because you did not consider the following condition in the code:

if (index >= denoms.length - 1) return 1; // one denom remaining 

And the last times to n is not correct and it is 1 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM