经典算法题每日演练——第三题 猴子吃桃

原文:经典算法题每日演练——第三题 猴子吃桃

 

        猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个。第二天早上又将剩下的桃子吃了一半,还是不过瘾又多

吃了一个。以后每天都吃前一天剩下的一半再加一个。到第10天刚好剩一个。问猴子第一天摘了多少个桃子?

 

分析: 这是一套非常经典的算法题,这个题目体现了算法思想中的递推思想,递归有两种形式,顺推和逆推,针对递推,只要

        我们找到递推公式,问题就迎刃而解了。

               令S10=1,容易看出 S9=2(S10+1), 简化一下 

                 S9=2S10+2

                 S8=2S9+2

                     .....

                 Sn=2Sn+1+2

 

遥想公瑾当年,老师说递归是最简洁,最容易理解的,好,就用递归试一下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             int sum = SumPeach(1);
 6
 7             Console.WriteLine("第一天摘得桃子有:{0}", sum);
 8
 9             Console.Read();
10         }
11
12         //递归
13         static int SumPeach(int day)
14         {
15             if (day == 10)
16                 return 1;
17
18             return 2 * SumPeach(day + 1) + 2;
19         }
20     }

 

当我们玩转递归的时候,老师说线性递归会将“变量,参数,返回值”在“递”的过程中压栈,如果迟迟“递”不到头的话,栈就会越积越多,

最后就爆掉了,window中系统默认的堆栈空间是1M。

那么解决方法是什么? 尾递归,下面我们继续上代码:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             int sum = SumPeachTail(1, 1);
 6
 7             Console.WriteLine("第一天摘得桃子有:{0}", sum);
 8
 9             Console.Read();
10         }
11
12         //尾递归
13         static int SumPeachTail(int day, int total)
14         {
15             if (day == 10)
16                 return total;
17
18             //将当前的值计算出传递给下一层
19             return SumPeachTail(day + 1, 2 * total + 2);
20         }
21     }

 

那么两种递归有什么区别呢?上图说话。

 

从图中我们可以清晰的看到“线性递归”和“尾递归”的区别,那到底有什么本质区别呢?尾递归中在每次向下递归的过程中,都会将当前

层的结果计算出来后向下一层传递,从理论上说,传到下一层后,上一层的参数值已经没有存在的必要了,可以清除上一层中的变量占

用的栈空间,那么最终达到的效果就是永远不会出现StackOverflowException了,但实际上是否真有这个效果,得要看编译程序是否

真的给你优化了。

下面我们将day=10改成day=int.MaxValue,跑一下程序看看:

很可惜,有图有真相,抛出异常了,当然我是菜鸟,早已看不懂汇编了,大家也可以讨论讨论,目前我个人认为C#编译器没有给

我做这个优化:-D。

 

下一步我们就要计算一下这个递归的时间复杂度是多少,关于求“递归”的时间复杂度主要有三种:

1.  代换法。

2.  递归树法。

3.  主定理。

 

这一篇我就说下代换法,作法如下

①:猜一下递归式复杂度的上界或者下界。

②:用数学归纳法证明你的复杂度是正确的。

 

为了具有通用性,我们将“猴子吃桃”的问题反过来写,也就是已知S1,求S10,当然原理是一样的,通用公式就有如下形式:

                 Tn=2Tn-1+2             ①  

假使           Tn=O(n)                   ②

则必定存在一个 c>0的自然数使

                Tn<=cO(n)=cn           ③

③代入①知 

                Tn<=2c(n-1)+2=2cn-2c+2

                                      =cn-c+1

                                      =cn-(c-1)

当c>=1时,则必有 Tn<=cn  

 

最后得出递归式的时间复杂度为O(N)。

 

时间: 2025-01-02 21:38:23

经典算法题每日演练——第三题 猴子吃桃的相关文章

经典算法题每日演练——第七题 KMP算法

原文:经典算法题每日演练--第七题 KMP算法       在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输 入法总是提示"看毛片"三个字,嘿嘿,就叫"看毛片算法"吧. 一:BF算法      如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知

经典算法题每日演练——第十七题 Dijkstra算法

原文:经典算法题每日演练--第十七题 Dijkstra算法         或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如"线性规划","动态规划" 这些经典策略,当然有的问题我们可以用贪心来寻求整体最优解,在图论中一个典型的贪心法求最优解的例子就莫过于"最短路径"的问题.   一:概序    从下图中我要寻找V0到V3的最短路径,你会发现通往他们的两点路径有很多:V0->V4-&g

经典算法题每日演练——第六题 协同推荐SlopeOne 算法

原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法               相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,"商品推荐","猜你喜欢",在实体店中我们有导购来为我们服务,在网络上 我们需要同样的一种替代物,如果简简单单的在数据库里面去捞,去比较,几乎是完成不了的,这时我们就需要一种协同推荐算法,来高效的推荐浏览者喜 欢的商品. 一:概念      SlopeOne的思想很简单,就是用均值化的思想来掩盖个体的打

经典算法题每日演练——第二十三题 鸡尾酒排序

原文:经典算法题每日演练--第二十三题 鸡尾酒排序     这篇我们继续扯淡一下鸡尾酒排序,为了知道为啥取名为鸡尾酒,特意看了下百科,见框框的话,也只能勉强这么说了.   要是文艺点的话,可以说是搅拌排序,通俗易懂点的话,就叫"双向冒泡排序",我想作为码农的话,不可能不知道冒泡排序, 冒泡是一个单向的从小到大或者从大到小的交换排序,而鸡尾酒排序是双向的,从一端进行从小到大排序,从另一端进行从大 到小排序. 从图中可以看到,第一次正向比较,我们找到了最大值9.             

经典算法题每日演练——第八题 AC自动机

原文:经典算法题每日演练--第八题 AC自动机        上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那么它的时间复杂度为O(c*(m+n)),c:为模式串的个数.m:为模式串的长度,n:为正文的长度,那 么这个复杂度就不再是线性了,我们学算法就是希望能把要解决的问题优化到极致,这不,AC自动机就派上用场了.    其实AC自动机就是Trie树的一个活用,活用点就是灌输了kmp的思想,从

经典算法题每日演练——第十题 树状数组

原文:经典算法题每日演练--第十题 树状数组         有一种数据结构是神奇的,神秘的,它展现了位运算与数组结合的神奇魅力,太牛逼的,它就是树状数组,这种数据结构不是神人是发现不了的. 一:概序      假如我现在有个需求,就是要频繁的求数组的前n项和,并且存在着数组中某些数字的频繁修改,那么我们该如何实现这样的需求?当然大家可以往 真实项目上靠一靠. ① 传统方法:根据索引修改为O(1),但是求前n项和为O(n). ②空间换时间方法:我开一个数组sum[],sum[i]=a[1]+..

经典算法题每日演练——第四题 最长公共子序列

一: 作用        最长公共子序列的问题常用于解决字符串的相似度,是一个非常实用的算法,作为码农,此算法是我们的必备基本功. 二:概念      举个例子,cnblogs这个字符串中子序列有多少个呢?很显然有27个,比如其中的cb,cgs等等都是其子序列,我们可以看出 子序列不见得一定是连续的,连续的那是子串.      我想大家已经了解了子序列的概念,那现在可以延伸到两个字符串了,那么大家能够看出:cnblogs和belong的公共子序列吗? 在你找出的公共子序列中,你能找出最长的公共子

经典算法题每日演练——第五题 字符串相似度

        这篇我们看看最长公共子序列的另一个版本,求字符串相似度(编辑距离),我也说过了,这是一个非常实用的算法,在DNA对比,网 页聚类等方面都有用武之地. 一:概念      对于两个字符串A和B,通过基本的增删改将字符串A改成B,或者将B改成A,在改变的过程中我们使用的最少步骤称之为"编辑距离". 比如如下的字符串:我们通过种种操作,痉挛之后编辑距离为3,不知道你看出来了没有? 二:解析   可能大家觉得有点复杂,不好理解,我们试着把这个大问题拆分掉,将"字符串

经典算法题每日演练——第二十题 三元组

         我们知道矩阵是一个非常强大的数据结构,在动态规划以及各种图论算法上都有广泛的应用,当然矩阵有着不足的地方就是空间和时间 复杂度都维持在N2上,比如1w个数字建立一个矩阵,在内存中会占用1w*1w=1亿的类型空间,这时就会遇到outofmemory...那么面 临的一个问题就是如何来压缩矩阵,当然压缩的方式有很多种,这里就介绍一个顺序表的压缩方式:三元组. 一:三元组     有时候我们的矩阵中只有零星的一些非零元素,其余的都是零元素,那么我们称之为稀疏矩阵,当然没有绝对的说有多