收银台算法问题
这是我目前碰到过的难度最大的一个算法题。
刚拿到手的时候简直一筹莫展,深受打击,大半个月都没再碰过FCC网站,觉得学习之路太过漫长,前途一片灰暗。
今天终于鼓起勇气看了下答案,具体实现我就不讲了,只讲一下这类复杂算法题的解题思路吧。
首先是问题的拆解,先从小处容易处着手,找到突破口,再由简入难,并抽象出可复用的功能函数,模块化地解决问题。要注意抽象出来的功能函数一定是跟具体的问题没有太大耦合的,否则就不算是一个好的抽象。
比如此题就是既然是找零,那首先就得得到抽屉里总共有多少零钱,要找零多少钱。要找零的钱可以通过顾客总共付了多少钱,商品一共多少钱来相减得到,抽屉里的零钱总数可以通过for循环提取第3个参数里信息得到。这个for循环就可以用一个函数封装,输入零钱数组,返回零钱总数。
这样就得到了第一个判断语句,如果零钱总数小于要找零的钱,那就返回“钱不够”;如果两者刚好相等,那就返回“刚刚好”。
现在关键的问题是怎么找零一个具体的数字,比如我要找零250元,该怎么找?首先我得确定抽屉里有几个100元的,然后几个50元的,然后用掉几张,就在原来的总数上减1。
以下是本算法的精髓所在
for (var i = cid.length - 1; i >= 0; i--) { // We loop over the cash-in-drawer array in reverse order. var coinName = cid[i][0], // We set the coin name. coinTotal = cid[i][1] * 100, // We set the total cash in that type of coin (times 100 for cents!). coinValue = getValue(coinName), // We get the value of a single coin/bill using it's name. coinAmount = coinTotal / coinValue, // We get the amount of coins of it's type by dividing the total cash by the value of a single unit. toReturn = 0; // Counter: How many coins of this type we are returning. while (changeLeft >= coinValue && coinAmount > 0) { // While change is greater that the value the current coin/bill: changeLeft -= coinValue; // Substract the value of a single coin/bill from the change left. coinAmount--; // Remove one coin/bill since we are returning it. toReturn++; // Add one to the counter. } // When the loop is done (because there is no coins/bills of the current // type left or the change left is less than the value of the current coin/bill) if (toReturn > 0) { // We push the coin and total to return in that type of coin/bill to the result. // We get this value by multiplying the value of a single coin/bill by it's value, and then divide by 100 to get the value in dollars. result.push([coinName, toReturn * coinValue / 100]); } }
遍历抽屉里的每一个面值,从最大的100元面值开始,先把100元面值这个名称提取出来,一会儿输出的时候要用,然后把100这个数字提取出来,(一般这种名和值一一对应的情况用列表查找的方式是最方便快捷的了,比如以前遇到的一道将阿拉伯数字转换成罗马数字的也是,先把所有的情况都列在一张二维数组里,最后直接在数组里面查找对应的名就可以得到相应的值了。),这里也用到了列表查找(仍旧抽象成一个函数),只不过没有二维数组那么复杂,只是一个switch语句而已,通过面值得到金额,然后我还要得到该面值拥有的数量,用上面两个值相除即可。
然后比较找零与该面值的大小,如果找零大于100,那就先找个100出来,然后数量-1,并把找出来的这个面值存到结果数组里。接着再比较剩下的钱是不是还大于100,如果仍大于100,那就再执行相同的操作,这里用while语句实现。
接着遍历50面值的,方法同上,依次类推,最后就得到了找零的数组。
但问题还没结束,因为我们不知道这个遍历结束后,找零是不是够了,所以我们再比较一下我们找出来的这个数组的总数与找零的金额是不是相等,如果不等,证明零钱不够找,返回“钱不够”,否则就可以直接返回该数组了。
问题就此解决。

浙公网安备 33010602011771号