当前位置: 首页 > news >正文

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

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

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

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

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


http://www.mrgr.cn/news/39201.html

相关文章:

  • 企业如何提升知识产权管理效率?
  • rocketmq集群模式介绍
  • 【AI大模型】Function Calling
  • Python NumPy 读取与保存数据:高效处理数据文件
  • 九块九付费进群系统 wxselect SQL注入漏洞
  • Foo a30 = Foo(123);会调用哪些构造函数
  • 第十四周学习周报
  • 先刮腻子还是先装柜子好呢?
  • 系统数据文件和信息
  • 从传统 RAG 到图 RAG,赋予大型语言模型更强大的知识力量
  • Unity3D 创建一个人物,实现人物的移动
  • C++中的多态(详细讲解)
  • 【Android 14源码分析】Activity启动流程-1
  • CO-DETR追踪损失函数情况
  • 谷歌收录批量查询,如何批量查询谷歌收录以及提交网站进行收录的方法
  • 服务器开通个人账户
  • 初识Linux以及Linux的基本命令
  • UFS 3.1架构简介
  • 关于git分支冲突问题
  • Dynamics 365 dependency EntityType