每当有人在商店或餐馆购物并用现金支付时,接受付款的人可能不得不把零钱还给他们。这就给那个人提出了一个简单的算法问题。给定要返回的零钱数量,他们必须确定返回给客户的硬币的最佳组合。幸运的是,实现这一优化的算法非常简单。
假设您需要向客户返还87美分。该算法包括首先向顾客提供最大面额硬币的最大可能数量。美国常用的最大面额硬币是25分硬币,所以我们一开始就尽量给顾客提供尽可能多的25分硬币,但不超过应付金额。要算出要给多少25分,最简单的方法是问25除以87等于多少。
这是我们可以在Python中通过一些简单的代码来计算的:
Amount = 87 quarters = Amount //25
这里我们必须小心地使用整数形式的除法,//,它将回答“25能被87整除几次?”
在确定要发放多少25分硬币后,我们必须减少应付金额,并对其他面额的硬币重复上述过程:
Amount = Amount - 25分*25角= Amount //10 Amount = Amount - 10角*10分= Amount //5便士= Amount - 5分*5
最后,我们必须设置打印语句来打印要发出的每枚硬币的数量。如果我们很小心,我们可能需要使用一些If -else语句来确保以正确的单数或复数形式打印名称。例如,这是打印多少硬币给客户的逻辑。
如果quarters > 1: print(str(quarters)+ " quarters") elif quarters == 1 print("1 quarter")
我上面展示的简单算法有些多余,因为您会发现自己在每一轮中使用较小的变量执行类似的步骤。主要的变体是每枚硬币值多少美分。为了使这个算法自动化,我们可以先把不同面值的分值放在一个列表中:
Values = [25,10,5,1]
然后我们可以编写一个循环,迭代这个硬币值列表,对每个新硬币类型执行重复的步骤。为了便于在循环中完成赢博体育这些操作,结果也必须放入列表中。我们可以很容易地做到这一点,从一个空的结果列表开始,并为我们处理的每个面额添加一个新条目。最后,我们还可以通过循环遍历各种硬币面额的名称来自动化打印结果的过程。
下面是一个程序change.py,它使用一对循环来自动执行算法中的关键步骤:
数量= 87面值=[25日10 5 1]名字=[(“季”、“季度”),(“分钱”,“角”)(“镍”、“硬币”)(“一分钱”,“便士”)]数= []d的教派:counts.append(数量/ / d)金额= % d结果=“我欠你”n范围(0,len(名字)):如果计算[n] = = 1:结果=结果+“1”+ [n][0] +名字”“elif计数[n] > 1: [n =结果+ str(计数结果 ]) + " " + [n][1] +名字”“打印(结果)
如果你仔细观察上面的代码,你会发现第二个循环必须遍历每个硬币的计数和相应的硬币名称。由于两个链表的长度相同,我们可以使用一个共同的索引变量n来同时遍历两个链表中的链表位置,以此来处理这个问题。由于我们正在使用索引变量,我们还必须使用列表索引符号count [n]和names[n]来处理我们正在迭代的两个列表。
用于同时遍历多个列表的另一种技术是从单个列表形成zip列表开始。例如,假设我们必须遍历一个水果名称和每磅价格的列表。使用循环索引,我们可以这样做:
Fruits =[‘橙子’,‘香蕉’,‘苹果’]prices = [1.45,0.45,1.15] for n in range(0,len(Fruits)): print(Fruits [n]+"s are $"+str(prices[n])+" per pound ")
另一种方法是形成一个zip列表,将来自两个列表的信息组合成一个元组列表。来形成zip列表
Both = zip(水果,价格)
这将产生一个新的列表,其结构为
[(“橙色”,1.45),(0.45“香蕉”),(“苹果”,1.15)]
然后,我们可以在这个压缩列表上建立一个迭代:
Fruits =[‘橙子’,‘香蕉’,‘苹果’]prices = [1.45,0.45,1.15] for fruit, price in zip(Fruits,prices): print(fruit+“s are $”+str(price)+“per pound”)
这个迭代的一个特殊技巧是循环的结构。由于我们是在元组的列表上迭代,因此列表中的每个元素都是一个元组。这里的特殊技巧是将每个元组赋值给由变量fruit和price组成的隐式元组。这将自动将迭代中每个元组的第一个元素赋值为fruit,第二个元素赋值为price。形成zip列表然后使用特殊迭代技巧的最终效果是,我们现在已经设法同时遍历两个列表。
以下是修改程序,在适当的地方重写为使用zip列表:
金额= 87面值=[25日10 5 1]名字=[(“季”、“季度”),(“分钱”,“角”)(“镍”、“硬币”)(“一分钱”,“便士”)]数= []d的教派:counts.append(数量/ / d)金额= % d =“我欠你”计数结果,名字在zip(数量、名称):如果count = = 1:结果=结果+“1”+名称[0]+”“elif数> 1:=结果+ str(计数结果 ) + " " + 名称[1]+”“打印(结果)
这是程序中最后需要改进的地方。当我们运行上面两个解决方案中的任何一个时,程序将打印
我欠你3 / 4美分1角2便士
这几乎是我们想要的,但如果有一些额外的标点符号就更好了。具体来说,我们希望在不同的结果之间有逗号,并在最后加上句号。
处理这个问题的一种方法是在每个结果之后打印一个逗号。这是不完全正确的,因为它会在末尾留下一个额外的逗号。更好的方法是在除第一个结果外的每个结果前打印一个逗号。为了处理这个问题,我们需要使用一个标志变量。我们引入了一个新变量didOne,可以用它来跟踪是否打印了第一个结果。在打印第一个结果后将该标志设置为true,然后使用该标志确定是否需要在下一个结果之前打印逗号。把句号放在最后也很容易做到。
对于这个版本,我恢复使用索引变量而不是zip列表。
amount = 87 denominations = [25,10,5,1] names = [('quarter','quarters'),('dime','dimes'),('nickel','nickels'),('penny','pennies')] counts = [] for d in denominations: counts.append(amount//d) amount = amount % d result = "I owe you " didOne = False for count,name in zip(counts,names): if count == 1: if didOne == True: result = result + ", " else: didOne = True;result = result + "1 " + name[0] elif count > 1:如果didOne == True: result = result + ", " else: didOne = True;结果=结果+ str(count) +" " + name[1] print(结果+".")
下面是最终版本的输出:
我欠你3个25分,1个一角,2个便士。