每天两题02
题目一:
思路:当n=1的时候很明显只有一种跳法;
当n>1的时候,那么总共的跳法应该就是第一次跳一级台阶还剩下n-1个台阶、第一次跳两级台阶还剩下n-2个台阶,这两种情况的总和,而至于这里的n-1和n-2个台阶,同理可以继续拆分,是不是觉得很熟悉,还是斐波那契数列,这里用的还是分治的思想,代码跟上一篇一样,不过还是写一下(省略最外层的类名,其实用递归是最容易的。。。。):
public static int jump(int n){ if (n == 1) { return 1; } if (n==2) { return 2; } int prepre=1; int pre=2; int current=0; for (int i = 2; i < n; i++) { current = prepre+pre; prepre = pre; pre = current; } return current; } public static void main(String[] args) { System.out.println(jump(4));//5 }
莫名感觉这种问题好有趣啊,哈哈哈
题目二:这个是题目一的强化版
先用递归试试:假设只有一个台阶的跳法为f(1),有两个台阶的跳法为f(2),三个台阶的跳法为f(3)。。。。
先试试n=5的时候,总共的跳法分为几种情况:第一次跳一个,那么还有4个台阶,这四个台阶的跳法为f(4); 如果第一次跳两个,剩下3个台阶,跳法为f(3),依次类推,还有f(2),f(1),那么f(5)=f(4)+f(3)+f(2)+f(1),到这里其实问题已经很明了了,那么f(n)==f(n-1)+f(n-2)+...+f(2)+f(1),再写一个f(n-1)==f(n-2)+f(n-3)+...+f(2)+f(1),将这两个等式减一下就可以得到f(n)=2f(n-1)
那么代码表示为:
public static int jump(int n){ if(n==1){ return 1; } return 2*jump(n-1); } public static void main(String[] args) { System.out.println(jump(3));//4 }
第二种方式:我们还是假设n=5,那么青蛙不管怎么样第五级台阶时肯定要跳到的,至于前面四个台阶,每一个台阶都不确定,要么跳到要么没有跳到,那么可能性就是2x2x2x2=16种可能,即2^4
可以很轻易的推出n级台阶总共的可能性为:2^(n-1),这种的话代码也就没什么好说的了
第三种:动态规划,动态规划也就是将计算的中间的状态给保存起来,避免下一次还要进行重复的计算,缺点很明显就是需要一定的内存空间
这种方法简单的说就是:假设有3个台阶,我只需要计算到第1个台阶的所有可能性,到第二个台阶的所有可能性,然后相加就是到第三个台阶的所有可能性;这里很有点不好理解,其实可以这样想,已经确定第一个台阶跳到第三个台阶和第二个台阶跳到第三个台阶这两种分类,那么我们只需要考虑青蛙从地上跳到第一个台阶的所有可能和跳到第二个台阶的所有可能,然后加起来就ok了,这里我们用一个数组存储中间状态:
public static int jump(int n){ int[] arr = new int[n]; //将数组arr每个位置都填充1 Arrays.fill(arr, 1); //外层的这个for循环就是分别计算第一个台阶、第二个台阶...第n个台阶的所有跳法 for (int i = 1; i < n; i++) //这个for循环的作用:比如计算第三个台阶,那么就需要将第一个台阶所有跳法加上第二个台阶所有跳法 for (int j = 0; j < i; j++) arr[i] += arr[j]; return arr[n - 1]; } public static void main(String[] args) { System.out.println(jump(8));//128 }