- 常见实现代码:
以下代码均为Java8实现
public class Main {
public static void main(String[] args) {
int fib = fib(10);
System.out.println(fib);//55
}
// 具体实现
static int fib(int N) {
if(N == 1 || N== 2){
return 1;
}else{
return fib(N-1)+fib(N-2);
}
}
}
但是这种实现形式性能效率极其低下:如获取fib(10),你需要获取fib(9)和fib(8),而在获取fib(9)的时候又需要去获取fib(8),导致存在大量重复计算,时间复杂度O(2^n)。
- 改进实现1-1:使用一个存储媒介(备忘录),把已计算的值存储,需要时则直接获取
public class Main {
static List<Integer> memo;
public static void main(String[] args) {
int fib = fib(10);
System.out.println(memo);//[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
System.out.println(fib);//55
}
//自顶向下
static int fib(int N) {
if (N < 1) {
return 0;
}
// 备忘录,容量为N+1,全初始化为 0
memo = new ArrayList<>(Collections.nCopies(N+1, 0));
// 进行带备忘录的递归
return helper(memo, N);
}
static int helper(List<Integer> memo, Integer n) {
if (n == 1 || n == 2){
memo.set(n,1);
return 1;
}
// 已经计算过则直接获取值
if (memo.get(n) != 0){
return memo.get(n);
}
memo.set(n,helper(memo, n - 1) + helper(memo, n - 2));
return memo.get(n);
}
}
在改进1-1中使用的是自顶向下法,即fib(10)->fib(9)…
也可以使用自底向上法实现
- 改进1-2:通过fib(1)=fib(2)=1,直接递归设置值到存储媒介中,获取对应值则从媒介中获取
public class Main {
static List<Integer> memo;
public static void main(String[] args) {
int fib = fib(10);
System.out.println(memo);
System.out.println(fib);
}
//自底向上
static int fib(int N) {
if (N < 1) {
return 0;
}
// 备忘录,容量为N+1,全初始化为 0
memo = new ArrayList<>(Collections.nCopies(N+1, 0));
// 进行带备忘录的递归
if (N == 1 || N == 2){
return 1;
}
memo.set(1,1);
memo.set(2,1);
for (int i = 3; i <= N; i++) {
memo.set(i,(memo.get(i-1)+ memo.get(i- 2)));
}
return memo.get(N);
}
}
自底向上和自顶向下都不需要重复计算,所以大大提高了效率,时间复杂度O(n);
- 改进1-3:为简化代码,降低空间复杂度,我们也可以如此实现
public class Main {
public static void main(String[] args) {
int fib = fib(10);
System.out.println(fib);
}
//状态压缩
static int fib(int N) {
if (N < 1) {
return 0;
}
int prev = 1, curr = 1;
for (int i = 3; i <= N; i++) {
int sum = prev + curr;
prev = curr;
curr = sum;
}
return curr;
}
}
- 附:动态规划详解