程序员数学 | 用递归将复杂的问题简单化(上)

在某些场景下,递归的解法⽐基于循环的迭代法更容易实现。

比如有四种⾯额的钱币,1元、2元、5元和10元,你⼀共需要给我10元,你可以给我1张10元,或者10张1元,或者5张1元外加1张5元等等。如果考虑每次的⾦额和先后顺序,那么最终⼀共有多少种不同的支付⽅式呢?

这个问题和之前的棋盘上放⻨粒有所不同,它并不是要求你给出最终的总数,⽽是在限定总和的情况下,求所有可能的加和⽅式。

但求和的重复性操作仍然是⼀样的,因此下面先使⽤迭代法尝试一下:

考虑当 k=1,2,3,…,n
当n=1的时候,可以取四种⾯额中的任何⼀种,那么奖赏就是1元、2元、5元和10元。
当n=2的时候,奖赏的总和有很多可能性。如果第⼀次奖赏了1元,那么第⼆次有可能取1、2、5元三种⾯额(如果取10,总数超过了10元)。

所以,在第⼀次奖赏1元,第⼆次奖赏1元后,总和为2元;第⼀次奖赏1元,第⼆次奖赏2元后,总和为3元;第⼀次奖赏1元,第⼆次奖赏5元后,总和为6元。依次类推。

迭代法也是可行的,但是如果⽤循环来实现要保存好多中间状态及其对应的变量。

这⾥不是要计算⼀个最终的数值,⽽是要列举出所有的可能性。

把复杂的问题简单化

将数学归纳法的思想泛化成更⼀般的情况

数学归纳法考虑了两种情况:

  1. 初始状态,也就是n=1的时候,命题是否成⽴;
  2. 如果n=k-1的时候,命题成⽴。那么只要证明n=k的时候,命题也成⽴。其中k为⼤于1的⾃然数。
    将上述两点顺序更换⼀下,再抽象化⼀下得出这样的递推关系:
  3. 假设n=k-1的时候,问题已经解决(或者已经找到解)。那么只要求解n=k的时候,问题如何解决/解是多少?
  4. 初始状态,就是n=1的时候,问题如何解决 / 解是多少?

这种思想就是将复杂的问题,每次都解决⼀点点,并将剩下的任务转化成为更简单的问题等待下次求解,如此反复,直到最简单的形式。

回到开头的例⼦,再将这种思想具体化:

  1. 假设n=k-1的时候,我们已经知道如何去求所有奖赏的组合。那么只要求解n=k的时候,会有哪些⾦额的选择,以及每种选择后还剩下多少奖⾦需要⽀付就可以了。
  2. 初始状态,就是n=1的时候,会有多少种奖赏。有了这个思路,就不难写出这个问题的递归实现。

递归和循环其实都是迭代法的实现,⽽且在某些场合下,它们的实现是可以相互转化的。但对于某些场景,递归就很难被循环取代。主要有两点原因:

⼀、递归的核⼼思想和数学归纳法类似,并更具有⼴泛性。这两者的类似之处体现在将当前的问题化解为两部分:

  1. ⼀个当前所采取的步骤。这种步骤可能是进⾏⼀次运算(例如每个棋格⾥的⻨粒数是前⼀格的两倍),或者做⼀个选择(例如选择不同⾯额的纸币),或者是不同类型操作的结合(赏⾦的案例)等等。

  2. 另⼀个更简单的问题。经过上述步骤之后,问题就会变得更加简单⼀点。这⾥“简单⼀点”,指运算的结果离目标值更近(例如赏⾦的总额),或者是完成了更多的选择(例如纸币的选择)。而“更简单的问题”,又可以通过嵌套调⽤,进⼀步简化和求解,直⾄达到结束条件。

⼆、递归会使用计算机的函数嵌套调用。⽽函数的调用本身,就可以保存很多中间状态和变量值,因此极⼤的方便了编程的处理。

我们只需要保证递归编程能够体现这种将复杂问题逐步简化的思想,那么它就能帮助我们解决很多类似的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Turbo正则

如果对您有用请我喝杯咖啡吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值