这篇翻译的文章以两种方式解决了相同的逻辑难题。第一种方式的编程风格接近大部分iOS开发者,实现了命令式编程的解决方案。第二种方法利用Swift的一些语言特性并实现函数式编程解决方案。源码可以在这里下载:https://github.com/ijoshsmith/break-a-dollarlogicpuzzle前段时间,一个朋友告诉我,有293种方法可以将1美元分解成更小的面额。换句话说,如果一个伙伴告诉你他有一美元,他手里有293种可能的组合,从两个50美分到四个25美分不等。第二天,我开始尝试用代码解决这个问题。这篇博客回顾了当时想到的两个解决方案。美元硬币对于不熟悉美元硬币的同学,可以先了解一下美元硬币。如下图,1dollar(美元)=100cents(美分):经过对问题的初步探索,我发现用比较简单粗暴的方法解决这个问题并不难,但是远从足够。我想找到一个优雅的解决方案,所以我尝试从各个角度思考这个问题,最终得到了我想要的答案。解决这个问题的关键在于递归分解问题。“如何用各种硬币组合来赚一美元”,更广泛地说,实际上是“如何用各种硬币组合来赚取指定的金额”。以人民币为例。你欠人家100块钱,人家说你不给我100块钱。你说好,我就给!所以我拿出两个50,就是50+50的解法。这时候,你发现有一张全新的50,你又不想把这50给他,于是你的问题就变成了:如何把你手里的50面额的钱和破钱组合起来。后来你把50换成5个10,就是50+10*5的解法,然后你觉得10中有一个是全新的,要不我可以用硬币换他。于是问题又变成了:如何组合10种面额的钱。就这样慢慢坏掉了。单击此处查看完整的算法评论。首先是硬币我多次提到“硬币”这个词。事实上,一枚硬币是一个整数值,而不是它值多少美分。我写了一个枚举类来存储所有硬币面额,然后使用静态方法按降序返回所有值:enumCoin:Int{caseSilverDollar=100caseHalfDollar=50caseQuarter=25caseDime=10caseNickel=5casePenny=1staticfunccoinsInDescendingOrder()->[Coin]{return[Coin.SilverDollar,Coin.HalfDollar,Coin.Quarter,Coin.Dime,Coin.Nickel,Coin.Penny,]}}解法一:命令式编程——命令式编程的一个重要思想是:变量变化状态。教学程序就像一个微控制器,告诉计算机如何做事。下面的Swift代码大家应该很熟悉,因为objc是命令式编程语言:funccountWaysToBreakAmout(amount:Int,usingCoinscoins:[Coin])->Int{letcoin=coins[0]if(coin==.Penny){return1}varsmallerCoins=[Coin]()forindexin1..!=coins.count{smallerCoins.append(coins[index])}varsum=0forcoinCountin0...(amount/coin.rawValue){letremainingAmount=amount-(coin.rawValue*coinCount)sum+=countWaysToBreakAmout(remainingAmount,usingCoins:smallerCoins)}returnsum}仔细看上面的代码,计算过程分为三步:首先取出可用数组中的第一个硬币,如果硬币已经是1美分,是最小的面额,所以没有进一步分裂的可能,直接返回1作为结束。然后创建一个数组(smallerCoins)存放比当前小的硬币,作为下次调用的参数。最后计算第一次取出的硬币去掉后有多少解。这样的代码在命令式编程中很常见,那么让我们看看如何用函数式编程来解决这个问题。方案二:函数式编程——Functional函数式编程的依赖对象是函数,不是状态变化。没有太多共享数据意味着更少的错误机会和更少的同步数据需求。Swift中的函数已经是一等公民,这使得高阶函数成为可能,即一个函数可以由其他函数组成。随着objc中blocks的引入,iOS开发者应该对这个不陌生了。这是我的功能解决方案:funccountWaysToBreakAmount(amount:Int,usingCoinscoins:Slice)->Int{let(coin,smallerCoins)=(coins[0],coins[1..
