22-JavaSE基础巩固练习:五道经典算法题

经典算法题

综合练习

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值