题目
第一题
import java.util.Scanner;
public class thirteen {
public static void main(String[] args) {
//创建scanner对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入兔子生活了多少个月");
//初始化time数据用于接收等会输入的数据
int time =0;
//循环,一旦输入的数据不符合,就会给出提示并从头开始
for (;;){
//接收数据
time = sc.nextInt();
//条件判断
if (time <= 2 || time >= 30) {
System.out.println("请重新输入一个数,要求再3-29之间");
return;
}else {
break;
}
}
//目标实现逻辑
int[] arr = new int[time];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < arr.length ; i++) {
arr[i] = arr[i-1] + arr[i-2];
}
System.out.println("过了" + time + "个月后兔子数量为" + arr[time-1]);
}
}
解题思路
1,这一类题目有一种相对简单的做法,可以先把题目要求以及结果手动算一下,往往算出几个就可以找出其中的规律。
或者说,一般的算法题都需要一个过程,你需要把题目的各种信息整合然后转换一种更直观更简单的过程。
以这道题为例,有题目的信息我们可以得知,从第一个月开始兔子数量是这样增加的。
1 1 2 3 5 8 13……
就能找到,当前这一项的数是前面两项相加的和,也就是经典的斐波那契数
2,有了当前这一项的数是前面两项相加的和的信息。我们就应该有了一个大致的轮廓,相加的目标是前两项(排序就需要用到数组),同时后面每一个数都需要这样运算(重复循环)
于是需要构建数组以及循环。
3,数组构建的核心就是,数组的长度,这道题目里面多少个月这个信息就可以用来当作数组长度信息,直接引用即可。值得注意的是思路是当前项是前面两项的和。
第一项和第二项是没有前面两项的。所以第一项和第二项需要单独赋值,而赋值的信息也可以从题目中拿到。兔子长大需要两个月,这两个月它是不会生产的。
循环的构建相对会复杂一点。i 的初始值应该是多少,i的边界判断应该是多少。先讲初始值,第一项和第二项是固定的且不属于这个规律里面,所以应当排除他们。所以i的初始应该为 2,i的边界判断应该就是数组的长度。
因为数组的特性int【0】的存在,所以第三项其实是int【2】,长度应该是最后一位的编号加一。
根据上面三点我们就可以构建出这个程序最核心的代码。
int[] arr = new int[time];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < arr.length ; i++) {
arr[i] = arr[i-1] + arr[i-2];
}
在和组员 许进彬的交流过程中还得知了另一种代码。整体思路与上面三点写的无异,唯一的区别就是将繁琐的数组删掉了。将当前数,前一个数和前第二个数单独拎了出来。
将前面两个数进行赋值,之后。
循环里面只需要将两个数相加之后就能得到当前数的值。
那么问题来了三个数也就只能进行一次计算,这道题的本质还是需要用到循环,三个数怎么做循环运算呢?
for(int i=2;i<n;i++){
c=a+b;
a=b;
b=c;
}
按照上面的代码,先将数算出来之后 ,对c 进行了运算。
然后用前面一个数去替换前面第二个数,再用c替换前面的第一个数。
这样新的a 和 b就会通过循环进入下一次运算,并且会得到新的结果。
这样的一个替换,替代了 之前的方法 通过创建数组来描写数列的先后顺序的办法。对代码进行了一个简化!!!!
还有第三种代码写法,两个字即可说清楚——递归。
递归是一种更加方便的方法,减轻了敲代码方面的负担,但是对思路的要求会比循环更高,只有学了才能搞清楚,所以这里不过多做赘述。
第二题
public class thirteen01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入小球的下落高度");
double M = sc.nextDouble();
if (M <= 0 || M >=2000) {
System.out.println("请输入1——1999之间的数");
return;
}
int N = sc.nextInt();
if (N <= 0 || N >= 50){
System.out.println("请输入1——49之间的数");
return;
}
double height = M;
double all = 0;
for (int i = 0; i < N; i++) {
height = height / 2;
all += height*3;
}
System.out.println(height);
System.out.println(all);
}
}
根据题目要求应该可以迅速得出,
回弹高度是前面一次高度的二分之一,这个逻辑可以很简单用代码表示。
关于弹跳路程的计算,我的思路是:最后一次回弹达到最高处时,他和上次往下落的路程加起来刚好时,回弹上升路程的三倍。而上一次的回弹路程和上上次下落的路程加起来同样也是三倍。于是就可以用后面计算出的新的回弹高度乘以3得到前面下落加上新的上升一共的路程。
而这样需要计算的路段数量和回弹次数一样刚好可以加入循环体里面一起循环。然后进行累加计算就可以得到全部路程的总长度。
for (int i = 0; i < N; i++) {
height = height / 2;
all += height*3;
}
结语
算法题目,更多的是需要对题目的信息进行整合,因为当前阶段代码的复杂度不会太高。你的思路总结越到位越简单,代码实现就越容易。而不是一开始就试图直接想用代码实现功能。对信息的拆解才是重点。
同时简单且功能强大的代码,并不是一次性编写出来的。对题目分析过后,要先有基础的思路然后在进行不断的优化,这样才可能写出相对简洁的代码。
以第一题为例子,三个方法一个思路,但是代码的简洁程度却在不断提高。
有了第一题这样的例子,我觉得对于自己写好的代码尝试优化是一个很好的习惯,也正是因为组里的交流,才会对这道题有了一个新的理解。