SICP 习题 (1.14)解题总结
SICP 习题 1.14要求计算出过程count-change的增长阶。count-change是书中1.2.2节讲解的用于计算零钱找换方案的过程。
要解答习题1.14,首先你需要理解count-change的工作方式,要理解count-change的工作方式,最好是自己去实现一遍count-change。
为了避免自己直接抄书中的代码,我决定自己实现一遍用来找换人民币的的“count-change”。事实上,我在看完并理解count-change的代码后,当我去实现人民币版的“count-change”时,我就强制自己不再回去看“count-change”的代码,保证自己有更多的主动思考。
有意思的是,当我实现完了回去看书上的代码,发现两者还是有挺大的区别,虽然算法是一样的,结果也都正确的。
首先我们得有个过程遍历各种零钱,我为了简化程序,只做了“元”的找换,“分”和“角”就略过了。
遍历各种零钱的过程如下,就是遍历“1元”,“2元”,“5元”,“10元”,“20元”,“50元”,“100元”这几种零钱。
这里就和书上有点差别,书上是记录现在还可以使用几种零钱,根据可以使用的零钱种类数量返回其中最大面值的金额。
我是简单粗暴地从最小面值遍历到最大面值。
(define (RMB-Change-Next-Kind change-kind)
(cond ((= change-kind 1) 2)
((= change-kind 2) 5)
((= change-kind 5) 10)
((= change-kind 10) 20)
((= change-kind 20) 50)
((= change-kind 50) 100)
(else 0)))
书中讲到的找换零钱的方法基于以下基本思路:
比如我们需要将100块的人民币找换成零钱,有几种找换方式?可以简单分为两种:有使用1块面额的,和没有使用1块面额的。
对于有使用1块面额的,把这一块钱去掉,剩99块,我们又可以继续看99块有几种找换方式。找到99块的所有找换方式,在加上现在这里去掉的1块钱,就是100块找换方式中有使用1块的所有找换方式。
对于没有使用1块面额的,我们就需要看看100块找成其它面额(不包含1块)的找换方式。
然后将上面两种类型的数量加起来就是100块的所有找换方式。
可以看到,以上的思路对应的是树形递归,每次递归调用分两路,一路调用的找换总额减少,一路调用的找换币种减少。
我的实现方法是下面这样的,和书上略有不同。
(define (RMB-Change-Recursive amount change-kind change-result)
(if (= amount 0) (format #t "Got one: ~S~%" change-result))
(cond ((= amount 0) 1)
((< amount 0) 0)
((= change-kind 0) 0)
(else (+ (RMB-Change-Recursive amount (RMB-Change-Next-Kind change-kind) change-result)
(RMB-Change-Recursive (- amount change-kind) change-kind (cons change-kind change-result))))))
如果对上面的过程不理解,建议回去读书中的1.2.2节,读懂为止。
好的,现在才到我们真正的题目了,第一个是找出11块的找换方式,这种比较容易,可以按以上的方式手工列出,也可以直接执行代码看看结果。
问题的第二部分比较麻烦,就是问,对于现金量的增长,以上过程的空间增长阶和时间增长阶是什么?
如果对增长阶的概念没有理解透,这题很难解。
我们先开始分析一下,如果发现过程中有不理解的,需要回去书上看看增长阶的内容。
首先来看看空间增长阶,当我们需要计算12块的找换方式时,比计算11块的找换方式需要增加多少内存?
当然,空间增长阶不能简单理解为需要增加多少内存,可能会有其它的空间需要,或者人家用纸算,根本不用内存,我们在这里就粗暴地将空间理解为内存吧。
增加多少内存呢?也不需要计算准确数字,只要计算大概的敏感度就好了。比如增长是线性的,多计算1块钱就多需要100K左右的空间。又或者是二次方曲线的增长,计算11块时需要11的二次方的空间,二计算12块时需要12的二次方的空间。这些就是我们要求的增长阶。
对于书中的count-change过程,空间增长阶是多少呢?
对于递归过程的空间增长阶,一般是去计算递归计算过程的最深深度。因为过程调用完以后,其使用的空间是会被释放的,我们需要计算的是被那些一直递归调用自己,目前还没有返回的过程所占用的空间。
同时需要注意每次递归调用的参数有没有累加,累加的形式是什么。
以上过程的递归嵌套最深的就是全部用1块来找换,嵌套深度就是要找换的金钱量,11块就是嵌套了11层,100块就是嵌套100层。而调用过程中参数没有累加,只是不断替换而已。
所以,count-change过程的空间增长阶是Theta[n]。
不过,我这里设计的过程好像有点不一样,为了打印所有可能的找换方式,我定义了一个参数用于保存目前计算过的暂时可行的零钱组合,就是参数change-resule。这个参数占用的空间是如何变化的呢?
可以发现,这个参数中的元素最多的时候就是全部找成1元的时候,这时候change-result中的值是:(1 1 1 …. 1)共有n个。而每次递归调用都有一个列表需要暂时保留,所以,当递归调用到最深层的时候,其实有n个列表,分别是(1) (1 1) (1 1 1) ….. (1 1 1 1 …. 1 1),所以这里占用的空间是1到n的累加。
所以我的RMB-Change过程的空间增长阶是Theta[n的累加],因为在求增长阶的时候只取多项式中最高阶的那项,Theta[n]就被忽略了。
以上是空间增长阶,那么步数的增长阶呢?或者说是时间增长阶呢?
书中习题要求的是步数的增长阶,我们一般假设执行计算的每一步都消耗等同的时间,所以时间的增长阶和步数的增长阶应该是一致的。有关这个假设是否正确后面的习题还有详细的讨论,目前暂时认为时间增长阶和步数的增长阶相同。
这个增长阶的求解过程比较复杂,我也到网上参考了好多别人的解法,有许多种思路。我总结了一个我个人比较容易理解的解法,描述如下:
以我这里的例子,找换面额种类有7种,分别是“1元”,“2元”,“5元”,“10元”,“20元”,“50元”,“100元”。
为了方便表达,我们用函数(T n m)来表示以上过程的时间复杂度,其中n是需要找换金额总数量,m是用于找换的零钱的面额的种类数量。
如果把1000元钱进行找换,可以把1000元的找换方式分为 “使用1元的” 和 “不使用1元的” 两种方式,就是:
(T 1000 7) = (T 999 7) + (T 1000 6)
而999元的找换方式又可以分为 “使用1元的” 和 “不使用1元的” 两种方式,就是:
(T 999 7) = (T 998 7) + (T 999 6)
如此不断分解,就可以得到1000个分支,每个分支带一个(T n 6)。
也就是所这里的(T n 7) = 1000 * (T n 6) = n * (T n 6)
再来计算(T n 6),在这里也就是( T 1000 6)
就是把1000元找换成“2元”,“5元”,“10元”,“20元”,“50元”,“100元”这6种零钱。
按上面相同的方法有:
(T 1000 6) = (T 998 6) + (T 1000 5)
(T 996 6) = (T 996 6) + (T 1000 5)
(T 994 6) = (T 994 6) + (T 1000 5)
....
按以上方法可以拆出500个分支(就是n/2个分支,因为这次是从2元开始找),每个分支带一个(T 1000 5)。
就有(T 1000 6) = n/2 * ( T 1000 5)
以此类推就有(T 1000 7) = n * ( n/2 * ( n/5 * ( n/10 * ( n/20 * (n/50 * (n/100)))))),其中的除数就是各个面额。
就有(T 1000 7 ) = (n 的 7次方)/10000000
因为我们在求增长阶,所以直接取增长阶为 (n 的 7次方)
虽然除数10000000也算是个很大的数,不过在n大到一定程度时,(n 的 7次方)就变成一个超级大的数,这时10000000也就不算什么了。
这同时也符合我们观察到的现象,当n很小时,实际需要的步数远小于(n 的 7次方)。
SICP 习题 (1.14)解题总结的更多相关文章
- SICP 习题 (1.13) 解题总结
SICP习题1.13要求证明Fib(n)是最接近φn/√5 的整数,其中φ=(1+√5)/2 .题目还有一个提示,提示解题者利用归纳法和斐波那契数的定义证明Fib(n)=(φn - ψn) / √5 ...
- SICP 习题 (1.7) 解题总结
SICP 习题 1.7 是对正文1.1.7节中的牛顿法求平方根的改进,改进部分是good-enough?过程. 原来的good-enough?是判断x和guess平方的差值是否小于0.001,这个过程 ...
- SICP 习题 (1.8) 解题总结
SICP 习题1.8需要我们做的是按照牛顿法求平方根的方法做一个求立方根的过程. 所以说书中讲牛顿法求平方根的内容还是要好好理解,不然后面这几道题做起来就比较困难. 反过来,如果理解了牛顿法求平方根的 ...
- SICP 习题 (1.9) 解题总结
SICP 习题 1.9 开始针对“迭代计算过程”和“递归计算过程”,有关迭代计算过程和递归计算过程的内容在书中的1.2.1节有详细讨论,要完成习题1.9,必须完全吃透1.2.1节的内容,不然的话,即使 ...
- SICP 习题 (1.10)解题总结
SICP 习题 1.10 讲的是一个叫“Akermann函数”的东西,去百度查可以查到对应的中文翻译,叫“阿克曼函数”. 就像前面的解题总结中提到的,我是一个数学恐惧者,看着稍微复杂一点的什么函数我就 ...
- SICP 习题 (1.41)解题总结
SICP 习题1.41 看似和周边的题目没有关系,突然叫我们去定义一个叫double的过程,事实上这道题的核心还是高阶函数. 题目要求我们定义一个过程double,它以一个过程作为參数,这个作为參数的 ...
- SICP 习题 (2.10)解题总结: 区间除法中除于零的问题
SICP 习题 2.10 要求我们处理区间除法运算中除于零的问题. 题中讲到一个专业程序猿Ben Bitdiddle看了Alyssa的工作后提出了除于零的问题,大家留意一下这个叫Ben的人,后面会不断 ...
- SICP 习题 (2.7) 解题总结 : 定义区间数据结构
SICP 习题 2.7 開始属于扩展练习,能够考虑不做,对后面的学习没什么影响.只是,假设上面的使用过程表示序对,还有丘奇计数你都能够理解的话,完毕这些扩展练习事实上没什么问题. 习题2.7是要求我们 ...
- SICP 习题 (2.6) 解题总结:丘奇计数
SICP 习题 2.6 讲的是丘奇计数,是习题2.4 和 2.5的延续. 这里大师们想提醒我们思考的是"数"究竟是什么,在计算机系统里能够怎样实现"数".准备好 ...
随机推荐
- UVa 10214 (莫比乌斯反演 or 欧拉函数) Trees in a Wood.
题意: 这道题和POJ 3090很相似,求|x|≤a,|y|≤b 中站在原点可见的整点的个数K,所有的整点个数为N(除去原点),求K/N 分析: 坐标轴上有四个可见的点,因为每个象限可见的点数都是一样 ...
- auto make System.map to C header file
#!/bin/bash # auto make System.map to C header file # 说明: # 该脚本主要是将Linux内核生成的System.map文件中的符号.地址存入结构 ...
- acdream 小晴天老师系列——晴天的后花园 (暴力+剪枝)
小晴天老师系列——晴天的后花园 Time Limit: 10000/5000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) ...
- 学习面试题Day03
1.Java中的注释有哪些? 如果不算Annotation,Java的注释有3种,即行注释.块注释和文档注释.它们往往适合于不同地方的注释,其中文档注释比较特殊,它的注释信息可以进入到javadoc文 ...
- nopcommerce商城系统--源代码结构和架构
这个文档是让开发者了解nopcommerce解决方案结构的指南.这是新的nopcommerce开发者学习nopcommerce代码的相关文档.首先,nopCommerce源代码是很容易得到的.它是一个 ...
- 在ASP.NET MVC中使用DropDownList
在ASP.NET MVC中,尽管我们可以直接在页面中编写HTML控件,并绑定控件的属性,但更方便的办法还是使用HtmlHelper中的辅助方法.在View中,包含一个类型为HtmlHelper的属性H ...
- HDU 1251-统计难题(Trie)
题意: 给一组单词 开始提问每次给一个串求该串是上面几个单词的前缀 分析: 没给数据规模,但用链表写ME好几次,又用数组写开小RE了,试了几次才过了,真是醉了... #include <map& ...
- LightOJ 1422 Halloween Costumes 区间dp
题意:给你n天需要穿的衣服的样式,每次可以套着穿衣服,脱掉的衣服就不能再穿了,问至少要带多少条衣服才能参加所有宴会 思路:dp[i][j]代表i-j天最少要带的衣服 从后向前dp 区间从大到小 更新d ...
- H5制作1--母亲节快乐
H5作品现在很流行额. 早上起的很早.就自己试着去了解了一下.感觉很easy. 用了百度的H5在线制作工具.感觉很easy.顺便给百度做下推广吧.h5.baidu.com 于是就有了自己的第一个dem ...
- HTTP协议 概述
本文主要说明一些 Http 相关的基本概念和基本知识,主要针对像我一样的初学者,知识主要来自于<Http 权威指南> 除了分享这些基本知识之外,笔者也是为将来找工作复习之用.(协议就是协议 ...