[Dart] 递归的逆向思维
前言
学习工作中经常会遇到一些需要重复做或者说需要遍历的问题,通常我们都会使用“循环”来作为解决方法。for循环,while循环写的贼6,对付这些常见的遍历问题它似乎总是能对症下药。一个for不能解决问题,那我就再嵌套个for。不可否认,循环能解决大部分问题,但很多时候用一种其他的办法能更快更简便地解决问题,这个方法就是递归。
我们写for循环时大部分时候是正向思维,体现在我们写for循环总是 i++,i 从0到n遍历,因为很多时候i++已经能解决问题了,如此长期以往,已经生成了固定正向思维。而,递归,则是要打破这种正向思维,它是从末到始,从未知到已知的遍历过程。
从数字求和开始
经典问题:求0-100所有的数字之和。
拿到问题,你马上写出一个for循环,这不是简简单单,叉着腰说,我的手已经触发肌肉记忆了,闭着眼都能写出来。
int getNum(int num) {
int sum = 0;
for (int i = 0; i <= num; i++) {
sum += i;
}
return sum;
}
此时你的同事默默抛出一个递归方法,产品经理走过来说,5行 < 7行,同事赢!
你突然想到你的代码还能更精简,马上说“我还能改”,可惜一晃眼同事们都去吃饭了。
其实并不是说递归方法少两行就是比循环的方法好,两种都是可行的解决方法,但不认识递归的话,我们每次只能想到第一种方法,技多不压身,能学就学,下面解析一下数字求和的递归代码。
int getNum(int num) {
if (num == 1) return 1;
final pre = getNum(num - 1);
return pre + num;
}
递归的结构
我们先拿出简单的数字求和递归方法,它虽然很简单,但却麻雀虽小五脏俱全,它就是递归函数的最基础的形态。
int fx(int n) {
if (n == 1) return 1; // row 1
final pre = fx(n - 1); // row2
return pre + n; // row3
}
row1:
递归函数最主要的一点是递归函数一定要有一个出口,如果没有出口,那它就会变成一个无限递归,也就是我们说的死递归。死递归是很可怕的,这是我们要避免的问题。所以我们我们递归的第一行就是出口,如上面方法的row1。而递归的出口是很容易找到的,一般就是问题的已知部分。在数字之和的问题中,我们都知道0+1的数字之和为1,所以我们就可以直接判定,如果num等于1时返回1。
`
row2:
如果是循环,我们是从1开始,一直遍历到n。但递归不是,递归教我们想问题要从未知到已知。
比如我们要计算1-5的数字之和,1是已知,而2,3,4,5我们都是未知,想要知道5的总和,我们要是能知道4的总和就好了,4的总和加上5就是5的总和了啊,想要知道4的总和又要了解3的总和......,所以我们想要知道n的总和,就要知道它的前一个n-1总和,而row2就是代表当前n的上一个总和。
row3:
我们通过row2知道了当前n的上一个数n-1的总和,接下来只要用上一个的总和加上自己就可以直接返回了。如此循环,直到到达n==1,才走出出口。
这样我们就大概了解了递归的基本结构,由以下组成
1:出口
2:当前n的上一个数n-1的结果fx(n-1)
3:fx(n-1)到fx(n)的条件
更多例子
计算数的阶乘
// 数的阶乘
int fx(int n) {
if (n == 1) return 1; // 出口
final pre = fx(n - 1); // 当前n的上一个数n-1的结果fx(n-1)
return pre * n; // fx(n-1)到fx(n)的条件
}
斐波那契数列
1、1、2、3、5、8、13、21、34、……
// 斐波那契数列
int fx(int n) {
if (n == 1 || n == 2) return 1;
final pre1 = fx(n - 1);
final pre2 = fx(n - 2);
return pre2 + pre1;
}
猴子吃桃问题
猴子吃桃问题:猴子第一天摘下若干个桃子,吃了一半,又多吃了一个。 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天都吃了 剩下的一半零一个。到第10天早上想再吃只剩一个了。求第一天共摘了多少个?
int fx(int n) {
if (n == 10) return 1;
final next = fx(n + 1);
return (next + 1) * 2;
}
总结:
总的来说,正如我在文中一直说的,递归是一种从未知到已知的遍历过程,在本文中只是浅浅谈了它的基本结构,我们要学习的不只是它的使用方法,还有它的逆向思维方式,从未知到已知,已知反馈给未知,我想这对于我们来说更重要。