经典算法题
综合练习
1、按照要求进行排序
-
定义数组并存储一些女朋友对象,利用Arrays中的sort方法进行排序。
-
要求:
-
(1)属性有姓名、年龄、身高
-
(2)按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序。
(姓名中不要有中文或特殊字符)
-
package com.app.comprehensive12.algorithm_test;
/*
定义女朋友类:
*/
public class GirlFriend {
// 要求:(1)属性有姓名、年龄、身高
private String name;
private int age;
private double height;
public GirlFriend() {
}
public GirlFriend(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return height
*/
public double getHeight() {
return height;
}
/**
* 设置
* @param height
*/
public void setHeight(double height) {
this.height = height;
}
public String toString() {
return "女朋友 {姓名:" + name + ", 年龄:" + age + "岁, 身高:" + height + "m}\n";
}
}
package com.app.comprehensive12.algorithm_test;
import java.util.Arrays;
import java.util.Comparator;
public class AlgorithmTest1 {
public static void main(String[] args) {
/*
经典算法题1:按照要求进行排序
需求:定义数组并存储一些女朋友对象,利用Arrays中的sort方法进行排序。
要求:
(1)属性有姓名、年龄、身高
(2)按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序。
(注意:姓名中不要有中文或特殊字符)
*/
// 创建一些女朋友对象
GirlFriend gf1 = new GirlFriend("zhaoliying", 23, 1.65);
GirlFriend gf2 = new GirlFriend("dengziqi", 27, 1.72);
GirlFriend gf3 = new GirlFriend("fanbingbing", 27, 1.75);
GirlFriend gf4 = new GirlFriend("angelababy", 27, 1.75);
// 定义数组存储女朋友对象
GirlFriend[] gfs = {gf1, gf2, gf3, gf4};
System.out.println("排序前:");
System.out.println(Arrays.toString(gfs));
System.out.println("-----------------------------");
// 利用Arrays中的sort方法进行排序
// 方式1:匿名内部类
/*Arrays.sort(gfs, new Comparator<GirlFriend>() {
@Override
public int compare(GirlFriend o1, GirlFriend o2) {
// 要求:(2)按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序。
// a.按照年龄大小进行排序
double temp = o1.getAge() - o2.getAge();
// b.如果年龄一样,则按照身高排序,否则还是按照年龄大小进行排序
temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
// c.如果年龄一样,身高一样,则按照姓名的字母进行排序,否则还是按照身高进行排序
// String类的compareTo方法:按字典顺序比较两个字符串。
temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;
// d.判断temp的值是否大于0
if (temp > 0) {
// 是,则返回1
return 1;
} else if (temp < 0) { // 判断temp的值是否小于0
// 是,则返回-1
return -1;
} else {
// 否,则说明temp的值等于0,返回0
return 0;
}
}
});*/
// 方式2:lambda表达式
Arrays.sort(gfs, (o1, o2) -> {
// 要求:(2)按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序。
// a.按照年龄大小进行排序
double temp = o1.getAge() - o2.getAge();
// b.如果年龄一样,则按照身高排序,否则还是按照年龄大小进行排序
temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
// c.如果年龄一样,身高一样,则按照姓名的字母进行排序,否则还是按照身高进行排序
// String类的compareTo方法:按字典顺序比较两个字符串。
temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;
// d.判断temp的值是否大于0
if (temp > 0) {
// 是,则返回1
return 1;
} else if (temp < 0) { // 判断temp的值是否小于0
// 是,则返回-1
return -1;
} else {
// 否,则说明temp的值等于0,返回0
return 0;
}
});
System.out.println("排序后:");
System.out.println(Arrays.toString(gfs));
}
}
排序前:
[女朋友 {姓名:zhaoliying, 年龄:23岁, 身高:1.65m}
, 女朋友 {姓名:dengziqi, 年龄:27岁, 身高:1.72m}
, 女朋友 {姓名:fanbingbing, 年龄:27岁, 身高:1.75m}
, 女朋友 {姓名:angelababy, 年龄:27岁, 身高:1.75m}
]
-----------------------------
排序后:
[女朋友 {姓名:zhaoliying, 年龄:23岁, 身高:1.65m}
, 女朋友 {姓名:dengziqi, 年龄:27岁, 身高:1.72m}
, 女朋友 {姓名:angelababy, 年龄:27岁, 身高:1.75m}
, 女朋友 {姓名:fanbingbing, 年龄:27岁, 身高:1.75m}
]
Process finished with exit code 0
2、不死神兔
-
问题:有一个很有名的数学逻辑题叫做不死神兔问题,有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第十二个月的兔子对数为多少?
-
分析:
-
解析:
-
空心圆代表未长大的1对小兔子,实心圆代表已长大的1对大兔子,并且兔子都不死
-
1月,1对小兔子未长大,用空心圆代表兔子未长大,因此1月份数量是1对
-
2月,1对小兔子长大了,用实心圆代表兔子长大了,因此2月份数量是1对
-
3月,1对大兔子生出了1对小兔子,1个实心圆和1个空心圆分别表示1对大兔子和1对小兔子,因此3月份数量是2对
-
4月,1对大兔子生出了1对小兔子,另1对小兔子也长大了,2个实心圆和1个空心圆分别表示2对大兔子和1对小兔子,因此4月份数量是3对
-
5月,2对大兔子生出了2对小兔子,另1对小兔子也长大了,3个实心圆和2个空心圆分别表示3对大兔子和2对小兔子,因此5月份数量是5对
-
6月,3对大兔子生出了3对小兔子,另2对小兔子也长大了,5个实心圆和3个空心圆分别表示5对大兔子和3对小兔子,因此6月份数量是8对
-
注意:此时规律已出现:
- 可以看到,从第三个月开始,后一个月的数量等于前两个月数量之和。
-
7月份数量 = 5月份数量5对 + 6月份数量8对,因此7月份数量是13对。
-
8月份数量是21对。
-
9月份数量是34对。
-
10月份数量是55对。
-
11月份数量是89对。
-
12月份数量是144对。
-
-
package com.app.comprehensive12.algorithm_test;
public class AlgorithmTest2 {
public static void main(String[] args) {
/*
经典算法题2:不死神兔
问题:有一个很有名的数学逻辑题叫做不死神兔问题,有一对兔子,
从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,
假如兔子都不死,问第十二个月的兔子对数为多少?
分析:
1月:1对
2月:1对
3月:2对
4月:3对
5月:5对
6月:8对
规律:
可以看到,从第三个月开始,后一个月的数量等于前两个月数量之和。
定论:从第三个数据开始,是前两个数据之和。(斐波那契数列)
*/
// 求解思路:
// 1.定义一个长度为12的数组,用于存储12个月兔子的对数量
int[] arr = new int[12];
// 索引:0 1 2 3 4 5 6 7 8 9 10 11
// 2.将1月和2月兔子的对数量分别存储到数组中的0、1索引位置,因为1、2月的数据是相同且固定的。
arr[0] = 1;
arr[1] = 1;
System.out.println("1月数量:" + arr[0] + "对兔子");
System.out.println("2月数量:" + arr[1] + "对兔子");
// 3.利用循环从2索引位置开始遍历数组,依次将其他月份的数据赋值到剩余的索引位置中
for (int i = 2; i < arr.length; i++) {
// 从第三个数据开始,是前两个数据之和
arr[i] = arr[i - 1] + arr[i - 2];
// 输出每个月份兔子的对数量
System.out.println((i + 1) + "月数量:" + arr[i] + "对兔子");
}
System.out.println("---------------------------");
// 求解思路:递归的方式
/*
1.递归的出口
2.找到递归的规律:
Fn(12) = Fn(11) + Fn(10);
Fn(11) = Fn(10) + Fn(9);
Fn(10) = Fn(9) + Fn(8);
...
Fn(3) = Fn(2) + Fn(1);
Fn(2) = 1;
Fn(1) = 1;
*/
System.out.println("12月数量:" + getSum(12) + "对兔子");
}
/**
* 递归方式解不死神兔难题
* @param month 月份
* @return 返回该月份兔子的对数量
*/
private static int getSum(int month) {
// 判断月份是否为1或2
if (month == 1 || month == 2) {
// 是,则返回1对兔子数量
return 1;
}else {
// 否,说明月份是大于2的,则利用递归方式计算该月份兔子的对数量
// 该月兔子的对数量 = 前两个月兔子的对数量之和
return getSum(month - 1) + getSum(month - 2);
}
}
}
1月数量:1对兔子
2月数量:1对兔子
3月数量:2对兔子
4月数量:3对兔子
5月数量:5对兔子
6月数量:8对兔子
7月数量:13对兔子
8月数量:21对兔子
9月数量:34对兔子
10月数量:55对兔子
11月数量:89对兔子
12月数量:144对兔子
---------------------------
12月数量:144对兔子
Process finished with exit code 0
3、猴子吃桃
- 问题:有一堆桃子,猴子第一天吃了其中的一半,并多吃了一个!以后每天猴子都吃当前剩下来的一半,然后再多吃一个,第10天的时候(还没吃),发现只剩下一个桃子了,请问,最初总共多少个桃子?
package com.app.comprehensive12.algorithm_test;
public class AlgorithmTest3 {
public static void main(String[] args) {
/*
问题:有一堆桃子,猴子第一天吃了其中的一半,并多吃了一个!
以后每天猴子都吃当前剩下来的一半,然后再多吃一个,
第10天的时候(还没吃),发现只剩下一个桃子了,请问,最初总共多少个桃子?
逆推:
day10: 1个桃子
day9: (day10 + 1) * 2 = 4,
题目中说以后每天猴子都吃当前剩下的一半,也就是4的一半:2,然后再多吃一个:2+1=3,
那么4-3=1,题目中说第10天的时候(还没吃),发现只剩下一个桃子了,因此该推论正确!
day8: (day9 + 1) * 2 = 10,
猴子吃一半,也就是10的一半:5,然后再多吃一个:5+1=6,那么10-6=4,
可以看到第9天剩下的桃子数量也是4,因此该推论正确!
1.递归的出口:
day == 10,剩下1个桃子
2.递归的规律:
每一天的桃子数量都是:后一天数量加1乘以2
*/
System.out.println("最初总共有" + getCount(1) + "个桃子~"); // 1534个桃子
}
/**
* 递归的方法解猴子吃桃难题
*
* @param day 第X天
* @return 返回第X天的桃子数量
*/
public static int getCount(int day) {
// 判断天数是否小于等于0 或 大于等于11
if (day <= 0 || day >= 11) {
// 是,说明天数错误
System.out.println("当前天数有误!");
return -1;
}
// 递归的出口:day == 10,剩下1个桃子
if (day == 10) {
return 1;
} else {
// 递归的规律:每一天的桃子数量是后一天数量加1乘以2
return (getCount(day + 1) + 1) * 2;
}
}
}
最初总共有1534个桃子~
Process finished with exit code 0
4、爬楼梯1
-
问题:可爱的小明特别喜欢爬楼梯,他有的时候一次爬一个台阶,有的时候一次爬两个台阶。如果这个楼梯有20个台阶,小明一共有多少种爬法呢?
-
运算结果:
1层台阶 1种爬法 2层台阶 2种爬法 7层台阶 21种爬法
package com.app.comprehensive12.algorithm_test;
public class AlgorithmTest4 {
public static void main(String[] args) {
/*
问题:可爱的小明特别喜欢爬楼梯,他有的时候一次爬一个台阶,有的时候一次爬两个台阶。
如果这个楼梯有20个台阶,小明一共有多少种爬法呢?
运算结果:
1层台阶 1种爬法
2层台阶 2种爬法
7层台阶 21种爬法
1.递归的出口:
台阶 == 1, 1种爬法
台阶 == 2, 2种爬法
2.递归的规律:
从第三个数据开始,是前两个数据之和。(斐波那契数列)
*/
System.out.println("1层台阶,小明一共有" + getCount(1) + "种爬法!");
System.out.println("2层台阶,小明一共有" + getCount(2) + "种爬法!");
System.out.println("7层台阶,小明一共有" + getCount(7) + "种爬法!");
System.out.println("20层台阶,小明一共有" + getCount(20) + "种爬法!");
}
public static int getCount(int n) {
// 1.递归的出口
// 判断台阶数是否为1
if (n == 1) {
// 是,返回1
return 1;
}
// 判断台阶数是否为2
if (n == 2) {
// 是,返回2
return 2;
}
// 2.递归的规律:从第三个数据开始,是前两个数据之和(斐波那契数列)
return getCount(n - 1) + getCount(n - 2);
}
}
1层台阶,小明一共有1种爬法!
2层台阶,小明一共有2种爬法!
7层台阶,小明一共有21种爬法!
20层台阶,小明一共有10946种爬法!
Process finished with exit code 0
5、爬楼梯2
-
问题:可爱的小明特别喜欢爬楼梯,他有的时候一次爬一个台阶,有的时候一次爬两个台阶,有的时候一次爬三个台阶。如果这个楼梯有20个台阶,小明一共有多少种爬法呢?
-
分析:
当只能走1级,2级台阶时,根据规律可以得出走法 k=f(n-1)+f(n-2); 当只能走1级,2级,3级台阶时,根据规律可以得出走法 k=f(n-1)+f(n-2)+f(n-3); 当只能走2级,3台阶时,根据规律可以得出走法 k=f(n-2)+f(n-3)。
package com.app.comprehensive12.algorithm_test;
public class AlgorithmTest5 {
public static void main(String[] args) {
/*
问题:可爱的小明特别喜欢爬楼梯,他有的时候一次爬一个台阶,
有的时候一次爬两个台阶,有的时候一次爬三个台阶。
如果这个楼梯有20个台阶,小明一共有多少种爬法呢?
1.递归的出口:
台阶 == 1, 1种爬法
台阶 == 2, 2种爬法
台阶 == 3, 4种爬法
2.递归的规律:
从第4个数据开始,是前3个数据之和。(斐波那契数列)
*/
System.out.println("1层台阶,小明一共有" + getCount(1) + "种爬法!");
System.out.println("2层台阶,小明一共有" + getCount(2) + "种爬法!");
System.out.println("3层台阶,小明一共有" + getCount(3) + "种爬法!");
System.out.println("4层台阶,小明一共有" + getCount(4) + "种爬法!");
System.out.println("7层台阶,小明一共有" + getCount(7) + "种爬法!");
System.out.println("20层台阶,小明一共有" + getCount(20) + "种爬法!");
}
/**
* 递归的方式解爬楼梯难题
* @param n 台阶数
* @return 返回台阶数的爬法数量
*/
public static int getCount(int n) {
// 1.递归的出口:
// 判断台阶数是否为1,是则返回1种爬法
if (n == 1) return 1;
// 判断台阶数是否为2,是则返回2种爬法
if (n == 2) return 2;
// 判断台阶数是否为3,是则返回4种爬法
if (n == 3) return 4;
// 2.递归的规律:从第4个数据开始,是前3个数据之和。(斐波那契数列)
return getCount(n - 1) + getCount(n - 2) + getCount(n - 3);
}
}
1层台阶,小明一共有1种爬法!
2层台阶,小明一共有2种爬法!
3层台阶,小明一共有4种爬法!
4层台阶,小明一共有7种爬法!
7层台阶,小明一共有44种爬法!
20层台阶,小明一共有121415种爬法!
Process finished with exit code 0