问题:
一个细胞,一小时分裂一次(一个变两个🥚),生命周期是三小时,求n小时后有多少细胞?
解法一:动态规划(拆分子问题)
先说明这个解法不咋好用,存在性能问题(我还专门画了图😓),希望可以给小伙伴们带来一些借鉴意义吧😊
分析
由题意可知,细胞生命周期共四个阶段,不如假设细胞消亡: 白色 -> 绿色 -> 黄色 -> 黑色
-
白色:新细胞,分裂一次后产生一个白色细胞,自己则变成绿色
-
绿色细胞再次分裂出一个白色细胞,自己则变成黄色
-
黄色细胞再次分裂出一个白色细胞,自己则变成黑色,黑色即生命周期结束
-
存活的细胞 = 白色 + 绿色 + 黄色,就是所求。
分析示意图
该思路,经过上面的分析,问题转化成几个子问题,即:分别计算出黄色、绿色和白色细胞的数量
代码展示
// 细胞分裂算法
/*
一个细胞,一小时分裂一次,生命周期是三小时,求n小时后有多少细胞?
细胞消亡: 白色 -> 绿色 -> 黄色 -> 黑色
白色:新细胞,分裂一次后产生一个白色细胞,自己则变成绿色
绿色细胞再次分裂出一个白色细胞,自己则变成黄色
黄色细胞再次分裂出一个白色细胞,自己则变成黑色,黑色即声明周期结束
存活的细胞 = 白色 + 绿色 + 黄色
*/
function total(n) {
var yellow = function (n) {
// 设置出口, 边界条件
if (n === 0 || n === 1) return 0
return green(n - 1)
}
var green = function (n) {
// 设置出口, 边界条件
if (n === 0) return 0
return white(n - 1)
}
var white = function (n) {
// 设置出口, 边界条件
if (n === 0) return 1
return white(n - 1) + green(n - 1) + yellow(n - 1)
}
return yellow(n) + green(n) + white(n)
}
console.log(total(0));
console.log(total(1));
console.log(total(2));
console.log(total(3));
console.log(total(4));
console.log(total(5));
/*
1
2
4
7
13
24
123
*/
小结
上面这个解法存在问题,没有“备份”,存在重复计算,测试发现 n>30 计算就非常非常困难了。我还没想出来怎么修改(后面我再看一下),读者可以借鉴一下这种思路,有大佬可以修正的烦请告知一下,在这先行谢过啦😃
解法二:——归纳法推荐✨
数学归纳法:由个别推出一般。归纳法适用于想解决一个问题转化为解决他的子问题,而他的子问题又变成子问题的子问题,而且我们发现这些问题其实都是一个模型,也就是说存在相同的逻辑归纳处理项
分析:
-
每次细胞分裂产生的新细胞(最新鲜的🥚),等于分裂前(上一次)的细胞总数(重点)
-
未开始计时之前,都是1个细胞, f(n) = 1, n <= 0
-
未开始有细胞死亡时,f(n) = 2 * n, n < 3
-
开始有细胞死亡时,f(n) = 2 * f(n - 1) - 死亡细胞数 ,n >= 3
| 时间(小时) | 细胞总数(个) |
|---|---|
| 0 | 1 |
| 1 | 2 |
| 2 | 4 |
| 3 | 7 |
| 4 | 13 |
| 5 | 24 |
| 6 | 44 |
关键在于求出死亡细胞数的表达式,下面且看我推演分析👇
已知细胞生命周期是三小时,所以:
- 第3小时后,第0小时的细胞死亡(思维陷阱 ❗),So,
f(3) = 2 * f(2) - f(0),这里的死亡细胞数是f(0)
依据f(3),姑且把公式定为:
f(n) = 2 * f(n-1) - f(n-3),(偷偷告诉你这是不对的,继续看👇)
- 第4小时后,第1小时的细胞死亡,So,
f(4) = 2 * f(3) - f(1),
显然这是不对的,因为f(1)两个细胞中的一个是f(0)的,在f(3)的时候已经死亡,不应该计算在内。所以要减去的这个死亡细胞数 = f(1)中的新生细胞数 ✔
- 第5小时后,第2小时的细胞死亡,但f(2)的4个细胞中2个已经死亡,所以死亡细胞数 = f(2)中的新生细胞
👉 从上面的分析来看,死亡细胞数并不是前3小时的细胞总数f(n-3) ,因为n-3时刻细胞总数 = 新生细胞 + 老细胞,老细胞在n时刻之前就已经死亡了。
因此,n时刻的死亡细胞数 应该是n-3时刻新生的细胞数,而n-3时刻新生的细胞数正是n-4时刻的总细胞数,即f(n-4),
🎉 所以,开始有细胞死亡时的正确计算公式是: f(n) = 2 * f(n-1) - f(n-4)
相比较,这个思路的整体代码就简单多了,请看👀
代码展示
function total02(n) {
if (n <= 0) {
return 1;
}
if (n < 3) {
return 2 * n;
}
if (n >= 3) {
return 2 * total02(n - 1) - total02(n - 4);
}
}
console.log("归纳法:");
console.log("0=", total02(0));
console.log("1=", total02(1));
console.log("2=", total02(2));
console.log("3=", total02(3));
console.log("4=", total02(4));
console.log("5=", total02(5));
console.log("6=", total02(6));
console.log("50=", total02(50));
/*
归纳法:
0= 1
1= 2
2= 4
3= 7
4= 13
5= 24
6= 44
50= 19426970897100
*/
小结
归纳包括完全归纳法和不完全归纳法。数学归纳法是一种完全归纳法。
从归纳法的过程不难看出,递归的数学模型其实就是归纳法。由个别推出一般,恰好跟演绎法相反,演绎法是从一般推出个别,所有数学证明都是演绎法。
🎈🎈🎈
🌹 本篇完,关注我,你会发现一个踏实努力的宝藏前端😊,让我们一起学习,共同成长吧。
🎉 喜欢的小伙伴记得点赞关注收藏哟,回看不迷路 😉
✨ 欢迎大家转发、评论交流
🧨 蟹蟹😊
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。