Coin change problem: difference between these two methods

Question:

I am implementing the coin change problem in python in CS50’s pset6. When I first tackled the problem, this was the algorithm I used:

import time

while True:
    try:
        totalChange = input('How much change do I owe you? ')
        totalChange = float(totalChange)  # check it it's a valid numeric value
        if totalChange < 0:
            print('Error: Please enter a positive numeric value')
            continue
        break
    except:
        print('Error: Please enter a positive numeric value')
start_time1 = time.time()
change1 = int(totalChange * 100)  # convert money into cents
n = 0
while change1 >= 25:
    change1 -= 25
    n += 1
while change1 >= 10:
    change1 -= 10
    n += 1
while change1 >= 5:
    change1 -= 5
    n += 1
while change1 >= 1:
    change1 -= 1
    n += 1

print(f'Method1: {n}')

print("--- %s seconds ---" % (time.time() - start_time1))

Having watched the lecture on dynamic programming, I wanted to implement it into this problem. This was my attempt:

while True:
    try:
        totalChange = input('How much change do I owe you? ')
        totalChange = float(totalChange)  # check it it's a valid numeric value
        if totalChange < 0:
            print('Error: Please enter a positive numeric value')
            continue
        break
    except:
        print('Error: Please enter a positive numeric value')
start_time2 = time.time()

change2 = int(totalChange*100)
rowsCoins = [1,5,10,25]
colsCoins = list(range(change2 + 1))
n = len(rowsCoins)
m = len(colsCoins)
matrix = [[i for i in range(m)] for j in range(n)]

for i in range(1,n):
    for j in range(1,m):
        if rowsCoins[i] == j:
            matrix[i][j] = 1
        elif rowsCoins[i] > j:
            matrix[i][j] = matrix[i-1][j]
        else:
            matrix[i][j] = min(matrix[i-1][j], 1 + matrix[i][j-rowsCoins[i]])

print(f'Method2: {matrix[-1][-1]}')

print("--- %s seconds ---" % (time.time() - start_time2))

When I run the program, it gives the correct answers, but it takes a much longer time.

  1. How could I adjust the second code so that it is correctly implementing dynamic programming. Is my problem that I am starting the loops from the top left corner of the matrix instead of the bottom right?
  2. What are the time complexities of the algorithms for each code that I wrote (as well as for a correct implementation of dynamic programming). I suspect that for the first code, it follows O(n^4), and for the second code O(n*m), and a correct implementation of dynamic programming should be O(n). Am I correct to think this?

Any help for a better understanding of these algorithms is much appreciated.

Asked By: Abdu M

||

Answers:

I think both algorithms are basically O(n).

n in this case is the size of the number entered.

In the first algorithm, it’s not O(n^4) as that would suggest you have 4 nested loops looping n times. Instead, you have 4 loops that run sequentially. If they didn’t modify change1 at all, that would potentially be O(4n), which is the same as O(n).

In the second algorithm, your choice of variable names confuses things a little. n is a constant, and m is based on the size of the input, so is what would typically be called n. So, if we rename n to c and m to n, we get O(c*n) which, again, is the same as O(n).

The key point here is that for any particular n, and O(n) algorithm isn’t necessarily faster than, say, an O(n^2) algorithm. Big O notation just describes how the amount of work done varies with the size of the input. What it does say, is that as n gets bigger, the time taken by an O(n) algorithm will increase slower than the time taken by an O(n^2) algorithm, so for some large enough n, the algorithm with the lower complexity will be quicker.

Answered By: SpoonMeiser

How could I adjust the second code so that it is correctly implementing dynamic programming. Is my problem that I am starting the loops from the top left corner of the matrix instead of the bottom right?

IMHO, this problem is not suitable for dynamic programming, so it is hard to implement the correct dp. Check a greedy solution https://github.com/endiliey/cs50/blob/master/pset6/greedy.py which should be the best solution.

What are the time complexities of the algorithms for each code that I wrote (as well as for a correct implementation of dynamic programming).

Basically both of your codes should be O(n), but it does not mean that they have the same time complexity, as you have said, the dp solution is much slower. That is because they have different factor(ratio). For example, 4n and 0.25n both are O(n) but they have different time complexity.

The greedy solution should have a time complexity of O(1).

Answered By: ZhaoGang
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.