同样的类型的题还有兔子繁殖的问题。
此题可以用丰富的解法来解答。
考察知识:[递归],[记忆化搜索],[动态规划], [递推]。
难度:一星
1 分治
分治思想简述
当一个问题规模较大且不易求解的时候,就可以考虑将问题分成几个小的模块,再逐一解决;
分治思想一般都会和递归一起使用,因为采用分治思想处理问题,其各个小模块通常具有与大问题相同的结构,这种特性也使递归技术有了用武之地。
所以,分治是一种思想,递归是一种技术!
1.1 分治 | 递归
大量重复计算,超时!
迭代 和 递归
对比两种实现方式,迭代和递归的区别是:迭代使用的是循环结构,递归使用的是选择结构;
使用递归能使程序的结构更清晰、更简洁、更容易让人理解,从而减少读懂代码的时间;
但是大量的递归调用会创建函数的副本,会消耗大量的时间和内存,而迭代则不需要;
递归函数分为调用和回退阶段,递归的回退顺序是它调用顺序的逆序。
public class Solution { public int Fibonacci(int n) { if(n<=1) return n; return Fibonacci(n-1) + Fibonacci(n-2); } }
1.2递归优化:记忆化搜索
用成员变量数组装着算过的数。 依旧反复递归调用自己,但用一个 if 判断来截断运算!!
public class Solution { int ans[] = new int[40]; public int Fibonacci(int n) { if(n<=1) return n; if (ans[n]!=0) return ans[n];// 减少递归次数的关键。 return ans[n]= Fibonacci(n-1) + Fibonacci(n-2); } }
2 动态规划
动态规划类似分治,同样是将原问题分解成子问题,通过求解子问题而得到原问题的解。但不同的是,动态规划是自底向上分解,并且会保存子问题的解,在需要时可直接拿过来使用,这一点是区别于分治的。
int Fibonacci(int n) { int ans[] = new int[40]; ans[1]=1; for (int i=2; i<=n; ++i) { ans[i] = ans[i-1] + ans[i-2]; } return ans[n]; }
2.1 动态规划优化:递推
我比较擅长这个。
public class Solution { public int Fibonacci(int n) { if(n == 0) return 0; }else if(n == 1) return 1; int sum = 0; int two = 0; int one = 1; for(int i=2;i<=n;i++){ sum = two + one; two = one; one = sum; } return sum; } }
2.2递推: 还可以优化,用更少的变量
这个一定要学习到。 用两个指针就可以完成遍历。
public class Solution { public int Fibonacci(int n) { if(n == 0) return 0; if(n == 1) return 1; int sum = 1; int one = 0; for(int i=2;i<=n;i++){ //找规律找出来的精华。 sum = sum + one; one = sum - one; } return sum; } }