找零问题:这两种方法的区别

时间:2018-12-31 12:38:53

标签: python algorithm big-o cs50

我正在CS50的pset6中的python中实现硬币找零问题。当我第一次解决该问题时,这就是我使用的算法:

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))

看了关于动态编程的讲座后,我想将其实现到这个问题中。这是我的尝试:

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))

当我运行程序时,它会给出正确的答案,但是会花费更长的时间。

  1. 如何调整第二个代码,以便它正确地实现动态编程。我的问题是我是从矩阵的左上角而不是右下角开始循环吗?
  2. 我编写的每个代码(以及正确执行动态编程)的算法的时间复杂度是多少?我怀疑对于第一个代码,它遵循O(n ^ 4),对于第二个代码,它遵循O(n * m),动态编程的正确实现应为O(n)。我认为正确吗?

我们非常感谢您对这些算法有更好的了解。预先感谢。

2 个答案:

答案 0 :(得分:0)

我认为这两种算法基本上都是O(n)。

n在这种情况下是输入数字的大小。

在第一个算法中,它不是O(n ^ 4),因为这将建议您有4个嵌套循环循环n次。相反,您有4个顺序运行的循环。如果他们根本不修改change1,则可能是O(4n),与O(n)相同。

在第二种算法中,您对变量名的选择使事情有些混乱。 n是一个常数,m是基于输入大小的,因此通常称为n。因此,如果将n重命名为c,将m重命名为n,则得到的O(c * n)与O(n)相同。

这里的关键点是,对于任何特定的n,O(n)算法不一定比O(n ^ 2)算法快。大O符号只是描述完成的工作量如何随输入的大小而变化。它的意思是,随着n变大,O(n)算法所花费的时间将比O(n ^ 2)算法所花费的时间 slower n足够多,复杂度较低的算法将更快。

答案 1 :(得分:0)

  

如何调整第二个代码,以便它正确地实现动态编程。我的问题是我是从矩阵的左上角而不是右下角开始循环吗?

恕我直言,此问题不适用于动态编程,因此很难实现正确 dp。检查一个贪婪的解决方案https://github.com/endiliey/cs50/blob/master/pset6/greedy.py,它应该是最好的解决方案。

  

我编写的每个代码(以及正确执行动态编程)的算法的时间复杂度是多少。

基本上,您的两个代码都应为O(n),但这并不意味着它们具有相同的时间复杂度,正如您所说,dp解决方案要慢得多。那是因为它们具有不同的因子(比率)。例如,4n0.25n都是O(n),但是它们具有不同的时间复杂度。

贪婪的解决方案的时间复杂度应为O(1)