Java经典编程题,你学废了吗?

        嗨喽~小伙伴们,大家早上好,中午好,晚上好呀, 

        记得最初学习C++ 的时候,用的是谭浩强教授的教材,上面有很多非常棒的习题,对于练习C++非常有帮助(话说,我没打广告🤣......),这些编程练习,实际上也可以用Java来实现。

        基础练习,虽然起点低,但留给我们思考的东西,可不止于实现功能

        这种练习网上一大堆,但我想写的是,通过这些练习来学习如何增强我们程序的健壮性

        现举例若干,以飨读者:

一: 

        给出一个百分制的成绩,

        要求输出成绩等级 'A', 'B', 'C', 'D', 'E',

        90分以上为'A', 80~90分为'B', 70~80分为'C', 60~70分为'D',60分以下为'E'。

        学习过编程的小伙伴们应该都练习过这道题,咱用Java实现如下:


import java.util.Scanner;

/**
 *
 * @author sixibiheye
 * @date 2021/10/12
 * @apiNote Java基础练习一:
 *          给出一个百分制的成绩,要求输出成绩等级'A','B','C','D','E',
 *          90分以上为'A',
 *          80~90分为'B',
 *          70~80分为'C',
 *          60~70分为'D',
 *          60分以下为'E'。
 *
 */

public class Question11 {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int grade;
        System.out.print("请输入您的成绩:");
        grade = scanner.nextInt();
        int gradeRank = grade / 10;

        // 0~59分统一设定为50分
        if(gradeRank <= 5){
            gradeRank = 5;
        }

        switch (gradeRank){
            case 10:
            case 9:
                System.out.println("您的成绩等级为:A"); break;
            case 8:
                System.out.println("您的成绩等级为:B"); break;
            case 7:
                System.out.println("您的成绩等级为:C"); break;
            case 6:
                System.out.println("您的成绩等级为:D"); break;
            case 5:
                System.out.println("您的成绩等级为:E"); break;
            default:
                System.out.println("您的输入有误!!!"); break;
        }

    }
}

        如果,我们输入:87,运行结果如下:

        看似没有问题,但是,这个程序有着致命的问题

        如果你作为一个用户,用这个程序去实现一个业务,如果你不小心输入了150,或者输入的不是整数92.7,甚至输入了字符串 ‘Haha’ ,咱这个程序还能运行吗?

        很明显可以看到,程序抛出了异常-----InputMismatchException ,从用户角度看,那就是软件卡死,使用不了了。

        所以,我们要保证,用户输入的任何内容,我们都能做出相应处理。即咱写的程序要有良好的健壮性

        针对此题,对于用户输入不是整数的Bug。咱可以尝试捕获异常。一旦用户输入的不是整数,就提醒用户重新输入

        还有一个Bug,如果用户输入的是整数,但不是0~100,尽管语法没错,但结果没有任何意义(逻辑错误),这个Bug咱也需要解决。

        综上,我们可以改善上述程序如下:


import java.util.InputMismatchException;
import java.util.Scanner;

/**
 *
 * @author sixibiheye
 * @date 2021/10/12
 * @apiNote Java基础练习一:
 *          给出一个百分制的成绩,要求输出成绩等级'A','B','C','D','E',
 *          90分以上为'A',
 *          80~90分为'B',
 *          70~80分为'C',
 *          60~70分为'D',
 *          60分以下为'E'。
 *
 */

public class Question11 {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int grade;

        while(true){
            System.out.print("请输入您的成绩:");
            try {
                
                grade = scanner.nextInt();
                if(grade <= 100 && grade >= 0){
                    break;
                }
                System.out.println("输入有误,成绩范围为0~100!");

            } catch (InputMismatchException e){
                System.out.println("您输入的成绩不是整数!");
                
                /*
                 * 前面的nextInt()读取数据后指针仍在当前行,
                 * 如果再执行grade = scanner.nextInt();
                 * grade读取到的是回车符,
                 * 此处用scanner.next()"吃掉"用户按下的回车键,保证下一次的
                 * grade = scanner.nextInt() 读取的是用户输入的内容,而不是回车符
                 *
                 */
                
                scanner.next();
            }
        }

        int gradeRank = grade / 10;

        // 0~59分统一设定为50分
        if(gradeRank <= 5){
            gradeRank = 5;
        }

        switch (gradeRank){
            case 10:
            case 9:
                System.out.println("您的成绩等级为:A"); break;
            case 8:
                System.out.println("您的成绩等级为:B"); break;
            case 7:
                System.out.println("您的成绩等级为:C"); break;
            case 6:
                System.out.println("您的成绩等级为:D"); break;
            case 5:
                System.out.println("您的成绩等级为:E"); break;
            default:
                System.out.println("您的输入有误!!!"); break;
        }

    }
}

        这样,不管用户输入啥,咱都能做出“友好”的处理:

 

  

二:   

        给一个不多于5位的正整数, 要求: 

        ①输出它是几位数

        ②分别打印出每一位数字 

        ③逆序打印出各位数字,例如原数为321,应输出123

        程序本身比较简单,实现如下:


import java.util.InputMismatchException;
import java.util.Scanner;

/**
 *
 * @author sixibiheye
 * @date 2021/10/12
 * @apiNote Java练习二:
 *          给一个不多于5位的正整数,要求:
 *          ①求出它是几位数:
 *          ②分别打印出每一位数字
 *          ③逆序打印出各位数字,例如原数为321,应输出123
 */
public class Question12 {
    public static void main(String[] args) {

        // 用一个数组存储个位,十位,百位,千位,万位
        int[] number = new int[5];
        // 位数
        int places;
        Scanner scanner = new Scanner(System.in);
        long num;
        while(true){
            System.out.print("请输入一个整数(0~99999):");
            try {
                num = scanner.nextLong();
                if(num <= 99999 && num >= 0){
                    break;
                }
                System.out.println("输入有误,整数范围为0~100!");

            } catch (InputMismatchException e){
                System.out.println("您输入的不是整数!");
                scanner.next();
            }
        }


        if(num > 9999) {
            places = 5;
        } else if(num > 999) {
            places = 4;
        } else if(num > 99) {
            places = 3;
        } else if(num > 9) {
            places = 2;
        } else {
            places = 1;
        }
        System.out.print(num + "是一个" + places + "位数,");

        // 计算第一位
        number[0] = (int)num/10000;

        // 计算第二位
        number[1] = (int)(num - number[0]*10000)/1000;

        // 计算第三位
        number[2] = (int)(num - number[0]*10000 - number[1]*1000)/100;

        // 计算第四位
        number[3] = (int)(num - number[0]*10000 - number[1]*1000 -number[2]*100)/10;

        // 计算第五位
        number[4] = (int)(num - number[0]*10000 - number[1]*1000 -number[2]*100 -number[3]*10);

        // 输出结果
        System.out.print("该数的各位数字分别为:");
        switch (places){
            case 5:
                for(int i = 0; i < 5; i++){
                    System.out.print(number[i]);
                    System.out.print(' ');
                }
                System.out.print(",逆序输出结果:");
                for(int i = 4; i >= 0; i--){
                    System.out.print(number[i]);
                }
                break;
            case 4:
                for(int i = 1; i < 5; i++){
                    System.out.print(number[i]);
                    System.out.print(' ');
                }
                System.out.print(",逆序输出结果:");
                for(int i = 4; i >= 1; i--){
                    System.out.print(number[i]);
                }
                break;
            case 3:
                for(int i = 2; i < 5; i++){
                    System.out.print(number[i]);
                    System.out.print(' ');
                }
                System.out.print(",逆序输出结果:");
                for(int i = 4; i >= 2; i--){
                    System.out.print(number[i]);
                }
                break;
            case 2:
                for(int i = 3; i < 5; i++){
                    System.out.print(number[i]);
                    System.out.print(' ');
                }
                System.out.print(",逆序输出结果:");
                for(int i = 4; i >= 3; i--){
                    System.out.print(number[i]);
                }
                break;
            case 1:
                for(int i = 4; i < 5; i++){
                    System.out.print(number[i]);
                    System.out.print(' ');
                }
                System.out.print(",逆序输出结果:");
                for(int i = 4; i >= 4; i--){
                    System.out.print(number[i]);
                }
                break;
            default:
                System.out.println("你输入的不合规范!");
        }

    }

}

        同样的,我们在while循环里对可能出现的Bug做了处理,保证程序的健壮性: 

        程序中最后的输出代码段略显冗杂,小伙伴们可以尝试着做出改善。 

         

三:

        企业发放的奖金来自利润提成。

        利润 i ≤ 100000的,可提成10%为奖金,

        100000< i ≤200000时,低于10万元的部分么时候按10%提成,高于10万元的部分可提成7.5%,

        200000< i ≤400000时,低于20万的部分仍按上述办法提成(下同),高于20万元的部分按5%提成,

        400000< i ≤600000时,高于40万元的部分按3%提成,

        600000< i ≤1000000时,高于60万元的部分按1.5%提成,

        i > 1000000时超过100万元的部分按1%提成,

        从键盘输入当月利润 ,输出应发奖金总数。

        要求:(1)用if语句编程序;  (2)用switch语句编程序

        只需要理清奖金的计算方式,很容易写出程序:


import java.util.Formatter;
import java.util.Scanner;

/**
 *
 * @author sixibiheye
 * @date 2021/10/12
 * @apiNote Java基础练习三
 *          企业发放的奖金来自利润提成,
 *          利润i≤100000的,可提成10%为奖金,
 *          100000<i≤200000时,低于10万元的部分么时候按10%提成,高于10万元的部分可提成7.5%,
 *          200000<i≤400000时,低于20万的部分仍按上述办法提成(下同),高于20万元的部分按5%提成,
 *          400000<i≤600000时,高于40万元的部分按3%提成,
 *          600000<i≤1000000时,高于60万元的部分按1.5%提成,
 *          i>10000时超过100万元的部分按1%提成,
 *          从键盘输入当月利润i,求应发奖金总数。
 *      要求:(1)用if语句编程序;
 *          (2)用switch语句编程序
 */
public class Question13 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 定义常量
        final double RATE_1 = 0.1f;
        final double RATE_2 = 0.075f;
        final double RATE_3 = 0.05f;
        final double RATE_4 = 0.03f;
        final double RATE_5 = 0.015f;
        final double RATE_6 = 0.01f;

        System.out.print("请输入当月利润:");
        double i = scanner.nextDouble();

        // 缩小量级
        i = i / 100000;


        // 方法一:用if语句
        // 奖金总数
        double y1;
        if (i <= 1) {
            y1 = i * RATE_1;
        } else if (i <= 2) {
            y1 = 1 * RATE_1 + (i - 1) * RATE_2;
        } else if (i <= 4) {
            y1 = 1 * RATE_1 + 1 * RATE_2 + (i - 2) * RATE_3;
        } else if (i <= 6) {
            y1 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + (i - 4) * RATE_4;
        } else if (i <= 10) {
            y1 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + 4 * RATE_4 + (i - 6) * RATE_5;
        } else {
            y1 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + 4 * RATE_4 + 6 * RATE_5 + (i - 10) * RATE_6;
        }

        // 保留两位小数
        String revenue1 = new Formatter().format("%.2f",y1*100000).toString();

        // 输出结果
        System.out.println("当月利润为" + i*100000 + "元的时候,奖金总数为:" + revenue1 + "元。");


        // 方法二:用switch语句
        // 奖金总数,先赋值为0
        double y2 = 0;
        int c = (int) i;
        if (c > 10){
            c = 10;
        }
        switch(c){
            case 0 : y2 = i * RATE_1; break;
            case 1 : y2 = 1 * RATE_1 + (i - 1) * RATE_2; break;
            case 2 :
            case 3 : y2 = 1 * RATE_1 + 1 * RATE_2 + (i - 2) * RATE_3; break;
            case 4 :
            case 5 : y2 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + (i - 4) * RATE_4; break;
            case 6 :
            case 7 :
            case 8 :
            case 9 : y2 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + 4 * RATE_4 + (i - 6) * RATE_5; break;
            case 10 : y2 = 1 * RATE_1 + 1 * RATE_2 + 2 * RATE_3 + 4 * RATE_4 + 6 * RATE_5 + (i - 10) * RATE_6; break;
            default:
                System.out.println("输入错误!"); break;
        }

        // 保留两位小数
        String revenue2 = new Formatter().format("%.2f",y2*100000).toString();

        // 输出结果
        System.out.println("当月利润为" + i*100000 + "元的时候,奖金总数为:" + revenue2 + "元。");


    }
}

        此程序中的代码稍显冗杂,也可以考虑一下如何精简我们的代码

        运行结果:

        此处用户有输入,所以为了保证程序的健壮性,同前面一样,可以对输入的数据进行限制,留给小伙伴们思考吧。 

 四:

        输入四个整数,要求按从小到大的顺序输出       

         排序算法是算法领域最基础的一种算法,此处提供四种基础算法:

  •          插入排序
  •          选择排序
  •          冒泡排序
  •          快速排序

        算法的原理在代码中说明:


import java.util.Scanner;

/**
 *
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习四:
 *          输入四个整数,要求按从小到大的顺序输出
 *
 *
 */
public class Question14 {

    /**
     * 插入排序算法
     *
     * 思想:
     * 假定第一个元素有序,
     * 取一个临时变量存放第二个元素的值,
     * 将第二个元素与第一个元素比较,
     * 如果第二个元素大于第一个元素,两个元素交换位置,否者,不做移动。
     * 继续,将临时变量的值改为第三个元素的值,
     * 第三个元素与第二个比较,
     * 如果小于第二个,将第二个元素向右移动,再与第一个元素比较,
     * 如果小于第一个,将第一个元素向右移,最后将临时变量的值放入第一个元素位置。
     *
     *
     */
    public static void insertSort (int[] numbers) {
        int size = numbers.length;
        for (int i = 1; i < size; i++) {
            // 保存每次需要插入的那个数
            int temp = numbers[i];
            int j;
            //把大于临时变量temp的数往后移动,不大于就不移动,最后空的位置就是temp的位置
            for (j = i; j > 0 && numbers[j - 1] > temp; j--) {
                numbers[j] = numbers[j - 1];
            }
            // 将temp放入这个位置
            numbers[j] = temp;
        }
        System.out.print("这四个数从小到大的顺序为:");
        for (int value : numbers) {
            System.out.print(value);
            System.out.print(' ');
        }
    }

    /**
     *
     * 选择排序算法
     *
     * 思想:
     * 对于第一个数,从后面的元素中找到最小的数与之交换
     * 再对第二个数,从后面的元素中找到最小的数与之交换
     * 直到最后一个数
     *
     */

    private static void selectSort (int[] numbers){
        int size = numbers.length;
        for(int i = 0; i < size; i++){
            for (int j = i + 1; j < numbers.length; j++) {
                if(numbers[i] > numbers[j]){
                    // 交换
                    int temp = numbers[i];
                    numbers[i] = numbers[j];
                    numbers[j] = temp;
                }
            }
        }
        System.out.print("这四个数从小到大的顺序为:");
        for (int value : numbers) {
            System.out.print(value);
            System.out.print(' ');
        }
    }

    /**
     *
     * 冒泡排序算法
     *
     * 思想:
     * 从第一个数开始,将自己与自己右边的一个数比较大小,如果大于右边的数,两个数交换位置,否则不交换,
     * 第一次外层循环结束,会找到最大的数,且被交换到最后一个位置
     * 第二次外城循环结束,会找到第二大的数,且被交换到倒数第二位置,
     * 如此下去,直到第一个数
     *
     *
     */

    private static void bubbleSort (int[] numbers) {
        int size = numbers.length;
        //外层循环控制排序多少趟
        for (int i = 0; i < size-1; i++) {

            //内层循环控制每趟排序多少次
            for (int j = 0; j < size-1-i; j++) {
                if(numbers[j] > numbers[j+1]) {
                    // 交换
                    int temp = numbers[j];
                    numbers[j] = numbers[j+1];
                    numbers[j+1] = temp;
                }
            }
        }
        System.out.print("这四个数从小到大的顺序为:");
        for (int value : numbers) {
            System.out.print(value);
            System.out.print(' ');
        }
    }

    /**
     *
     * 快速排序算法
     *
     * 思想:
     * 1. 将第一个数存入一个临时变量,作为基准数,
     * 2. 先从后往前,找到第一个比基准数小的数(记录该数的位置,我们用R表示),
     * 3. 再从前往后,找到第一个比基准数大的值(记录该数的位置,我们用L表示),
     * 4. 交换R和L位置对应的数
     * 5. 重复2,3,4步
     *
     * 直到 L=R,结束该次循环,此时将基准数放到L(R)位置,
     *
     * 这时基准数左边的数都比基准数小,右边的数都比基准数大,
     * 把基准数左边的数看作一个新的数组,重复 1,2,3,4 步
     * 把基准数右边的数看作一个新的数组,重复 1,2,3,4 步 (利用递归)
     *
     *
     */

    // 先排序
    private static void quick(int[] numbers,int l ,int r) {
        int start = l;
        int end = r;
        if (l >= r) {
            return;
        }
        // 基准数
        int key = numbers[l];
        // 如果L和R不相同
        while (l < r) {
            // 从后往前,找到第一个比基准数小的数,记录该数的位置
            while (l < r && key <= numbers[r]) {
                r -= 1;
            }
            // 交换这两的位置
            numbers[l]=numbers[r];
            // 从前往后,找到第一个比基准数大的值,记录该数的位置
            while (l < r && key >= numbers[l]) {
                l += 1;
            }
            // 交换这两的位置
            numbers[r] = numbers[l];
        }
        // 将基准数放到L(R)位置,注意此时numbers[r] = numbers[l]
        numbers[l] = key;
        // 一直递归即可
        quick(numbers, start, l - 1);
        quick(numbers, l + 1, end);


    }

    // 再输出结果
    private static void quickSort(int[] numbers,int l ,int r){
        quick(numbers,l,r);
        System.out.print("这四个数从小到大的顺序为:");
        for (int value : numbers) {
            System.out.print(value);
            System.out.print(' ');
        }
    }



    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 用数组存储这四个数
        int[] numbers = new int[4];
        // 用户输入
        System.out.print("比较大小,请输入第一个整数:");
        numbers[0] = scanner.nextInt();
        System.out.print("比较大小,请输入第二个整数:");
        numbers[1] = scanner.nextInt();
        System.out.print("比较大小,请输入第三个整数:");
        numbers[2] = scanner.nextInt();
        System.out.print("比较大小,请输入第四个整数:");
        numbers[3] = scanner.nextInt();

        //方法一:插入排序
        insertSort(numbers); System.out.println(); //换行

        //方法二:选择排序
        selectSort(numbers); System.out.println(); //换行

        //方法三:冒泡排序
        bubbleSort(numbers); System.out.println(); //换行

        //方法四:快速排序
        quickSort(numbers,0,numbers.length - 1); System.out.println(); //换行


    }
}

         同样的,可以对用户输入作出限制,小伙伴们自己实现吧。运行结果如下:

 五:

        输人两个正整数m和n,求其最大公约数和最小公倍数

              一道典型练习,此处提供三种思路:


import java.util.ArrayList;
import java.util.Scanner;

/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习五:
 *          输人两个正整数m和n,求其最大公约数和最小公倍数
 */
public class Question15 {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.print("求最大公约数和最小公倍数,请输入第一个数:");
        int a = scanner.nextInt();
        System.out.print("第二个数:");
        int b = scanner.nextInt();

        // 计算二者乘积,用于计算最小公倍数
        int muti = a * b;


        // 方法一:穷举法
        int gcd1 = getGCD1(a,b);
        int lcm1 = muti / gcd1;
        System.out.println("穷举法求这两个数的最大公约数是:" + gcd1 + ",最小公倍数是:" + lcm1 + '。');

        // 方法二:质因数法
        int gcd2 = getGCD2(a,b);
        int lcm2 = muti / gcd1;
        System.out.println("质因数法求这两个数的最大公约数是:" + gcd2 + ",最小公倍数是:" + lcm2 + '。');

        // 方法三:辗转相除法
        int gcd3 = getGCD3(a,b);
        int lcm3 = muti / gcd1;
        System.out.println("辗转相除法求这两个数的最大公约数是:" + gcd3 + ",最小公倍数是:" + lcm3 + '。');

    }

    /**
     * @description
     *     穷举, 从较小的数往前穷举, 速度较慢
     *
     * @param num1 第一个数
     * @param num2 第二个数
     * @return 最大公约数
     *
     */
    public static int getGCD1(int num1, int num2) {

        // 支持负数
        num1 = Math.abs(num1);
        num2 = Math.abs(num2);

        // 找到小的那个数穷举, 直接从较小数开始
        int gcd = Math.min(num1, num2);
        while (gcd > 1) {
            // 如果 gcd 能被两个数同时约分,则就是最大公约数,注意是往前穷举
            if (num1 % gcd == 0 && num2 % gcd == 0) {
                // 直接返回最大公约数
                return gcd;
            }
            // 否则 gcd 继续减小,往前穷举
            gcd--;
        }

        return gcd;
    }


    /**
     *
     * @return 返回一个数的质因子序列(数组形式), 这里忽略1
     *
     */

    public static ArrayList<Integer> getPrimeFactors(int num) {
        // 创建一个数组用于存储所有的质因子
        ArrayList<Integer> factorList = new ArrayList<>();
        int i = 2;

        while (i <= num) {

            // 如果i是num的因子
            if (num % i == 0) {
                // 就加入序列
                factorList.add(i);
                // 下一个质因子一定小于num / i
                num /= i;
                // i从2开始
                i = 2;
            } else {
                // 否则继续
                i++;
            }
        }

        return factorList;
    }

    /**
     *
     * @description
     *      质因数分解法,将两个数的所有质因子分解出来,
     *      然后将公共的因子相乘,得到的就是最大公约数,速度比较慢
     *
     * @param num1 第一个数
     * @param num2 第二个数
     * @return 最大公约数
     *
     *
     */
    public static int getGCD2(int num1, int num2) {

        // 支持负数
        num1 = Math.abs(num1);
        num2 = Math.abs(num2);

        // 获得两个数的质因子序列
        ArrayList<Integer> factors1 = getPrimeFactors(num1);
        ArrayList<Integer> factors2 = getPrimeFactors(num2);

        // 先初始化
        int gcd = 1;

        // 从头开始找公共的质因子,相乘起来
        for (Integer factor : factors1) {
            int size = factors2.size();
            for (int j = 0; j < size; j++) {
                if (factor.equals(factors2.get(j))) {
                    // 将公共的质因子累乘
                    gcd *= factor;
                    // num2的质因子序列要去掉已经找到的,防止重复找
                    factors2.remove(j);
                    // 此处一次只找一对公共的质因子,减少循环次数
                    j = factors2.size();
                }
            }
        }

        return gcd;
    }

    /**
     * @description
     *          辗转相除法, 高效稳定 <br>
     *          原理: gcd(a, b) = gcd(b, a mod b)
     * @param num1 第一个数
     * @param num2 第二个数
     * @return 最大公约数
     *
     */
    public static int getGCD3(int num1, int num2) {
        // 支持负数
        num1 = Math.abs(num1);
        num2 = Math.abs(num2);

        // 先使得num1小于num2,便于使用辗转相除法
        if(num1 > num2){
            int temp = num1;
            num1 = num2;
            num2 = temp;
        }

        while(num1 != 0){
            //余数
            int r = num2 % num1;
            num2 = num1;
            num1 = r;
        }

        return num2;
    }

}

        思路很简单,但需要注意一些细节,在注释中都有说明。运行结果如下:

六:

        输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数

        此处如何统计应该是本题的一个难点。笔者暂时还没有找到更好的办法,只能使用正则表达式,提供如下思路:


import java.util.*;

/**
 *
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习六:
 *          输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数
 *
 */

public class Question16 {
    public static void main(String[] args) {
        System.out.print("请输入一串字符:");
        Scanner scan = new Scanner(System.in);
        String str = scan.nextLine();
        // 统计
        count(str);
    }

    private static void count(String str) {
        // 利用正则表达式
        String E1 = "[a-zA-Z]";
        String E2 = "[0-9]";
        //空格
        String E3 = "\\s";

        int countLetter = 0;
        int countNumber = 0;
        int countSpace = 0;
        int countOther = 0;

        // 若含有汉字,需将字符串转化为字符数组,再添加进一个字符串数组中
        char[] arrayChar = str.toCharArray();
        String[] arrayString = new String[arrayChar.length];

        // System.out.println(Arrays.toString(arrayString));
        // 将 "我是Grace!" 转化为 ['我','是','G','r','a','c','e','!']
        for(int i=0;i<arrayChar.length;i++) {
            arrayString[i] = String.valueOf(arrayChar[i]); // String.valueOf()用于转化为字符串
        }

        //遍历字符串数组中的元素
        for (String s : arrayString) {
            if (s.matches(E1)) {
                countLetter++;
            } else if (s.matches(E2)) {
                countNumber++;
            } else if (s.matches(E3)) {
                countSpace++;
            } else {
                countOther++;
            }
        }

        // 输出统计结果
        System.out.println("输入的字母个数:" + countLetter + ',');
        System.out.println("输入的数字个数:" + countNumber + ',');
        System.out.println("输入的空格个数:" + countSpace + ',');
        System.out.println("输入的其它字符个数:" + countOther + '。');

    }

}

         此处用到了许多零碎的知识,比如正则表达式,String的valueOf()方法,toCharArray()方法等,请小伙伴们好好回顾一下这些零碎的东西。

         小伙伴们如果有其他更好的方法,欢迎评论。

         运行结果如下:

七:

        求Sn=a+aa+aaa+…+aaa...(n个a)之值 , 其中a是一个数字。

        例如:2 + 22 + 222 + ... +222...(n个2) = ?

         程序编写本身不会有很大的问题,如下:


import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习七:
 *          求Sn=a+aa+aaa+…+aaa...(n个a)之值,其中a是一个数字。
 *          例如:2 + 22 + 222 + ... (n个2)
 *
 */

public class Question17 {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        int a , n;
        // 输入控制
        while(true){
            try {
                System.out.print("请输入数字a:");
                a = scanner.nextInt();
                if(a < 0 || a >9){
                    System.out.println("数字,只能是0~9!");
                    continue;
                }
                System.out.print("请输入整数n:");
                n = scanner.nextInt();
                break;
            } catch (InputMismatchException e){
                System.out.println("输入有误,请输入一个整数!");
                scanner.next();
            }
        }


        // sn为总和,tn为aaa...
        long sn = 0, tn =0;
        for (int i = 0; i < n; i++) {
            tn += a;
            sn += tn;
            a *= 10;
        }

        System.out.println("a+aa+aaa+...+aaa...(n个a) = " + sn);
    }
}

        我们对用户的输入做了简单的控制,运行如下:

        但是,很显然,这个程序对于n非常大的情况就无能为力了,比如:

 

        根本原因在于,100个4连起来的数已经超过了Java中Long型数据的最大值(2^{63}-1了,一个解决方式为,将变量sn , tn改为float类型(范围大约为:-10^{38}\sim10^{38})或者double类型(范围大约为: -10^{300}\sim10^{300}),改成double类型后,尝试运行如下:  

         确实要比Long类型的范围大许多,但是,如果我们追求完美的话,当n > 1000时,这个结果又出Bug了。

        对于整数的最大值,利用Java中的基础数据类型显然是无法解决上述问题的。

        其实,Java中的 math 库提供了一个 BigInteger 类专门用于处理大数。有多大呢?理论上,只要你的内存够大,它可以装下任何一个整数。

        简单介绍一下这个类。它的构造方法传入一个字符串:

BigInteger bigInt1 = new BigInteger("10000000000000000");
BigInteger bigInt2 = new BigInteger("20000000000000000");

        此时对象bigInt1便储存了10000000000000000这个数据,而这个数据可以非常大,比如10^{1000} 。

        注意此处的 bigInt1 , bigInt2 的类型是 BigInteger ,因此无法使用简单的

        +  ,  - ,  \times ,  \div ,

        等运算符号对bigInt1 , bigInt2进行运算,但在这个类中提供了加减乘除等基础运算对应的方法


import java.math.BigInteger;
 
public class BigIntegerDemo {
 
	public static void main(String[] args) {
		BigInteger bi1 = new BigInteger("123456789") ;	// 声明BigInteger对象
		BigInteger bi2 = new BigInteger("987654321") ;	// 声明BigInteger对象
		System.out.println("加法操作:" + bi2.add(bi1)) ;	// 加法操作
		System.out.println("减法操作:" + bi2.subtract(bi1)) ;	// 减法操作
		System.out.println("乘法操作:" + bi2.multiply(bi1)) ;	// 乘法操作
		System.out.println("除法操作:" + bi2.divide(bi1)) ;	// 除法操作
		System.out.println("最大数:" + bi2.max(bi1)) ;	 // 求出最大数
		System.out.println("最小数:" + bi2.min(bi1)) ;	 // 求出最小数
		BigInteger result[] = bi2.divideAndRemainder(bi1) ;	// 求出余数的除法操作
		System.out.println("商是:" + result[0] + 
			";余数是:" + result[1]) ;
	}
}

        利用 BigInteger 类,上述问题便可以更为完美地解决,实现如下:


import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习七:
 *          求Sn=a+aa+aaa+…+aaa...(n个a)之值,其中a是一个数字。
 *          例如:2 + 22 + 222 + ... (n个2)
 *
 */

public class Question17 {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        int a , n;
        while(true){
            try {
                System.out.print("请输入数字a:");
                a = scanner.nextInt();
                if(a < 0 || a >9){
                    System.out.println("数字,只能是0~9!");
                    continue;
                }
                System.out.print("请输入整数n:");
                n = scanner.nextInt();
                break;
            } catch (InputMismatchException e){
                System.out.println("输入有误,请输入一个整数!");
                scanner.next();
            }
        }

        // sn为总和,tn为aaa...
        BigInteger sn = new BigInteger("0");
        BigInteger tn = new BigInteger("0");
        BigInteger ten = new BigInteger("10"); // 常量10
        // String.valueOf(a) 用于将a转化为字符串类型
        BigInteger aa = new BigInteger(String.valueOf(a));

        for (int i = 0; i < n; i++) {
            tn = tn.add(aa);
            sn = sn.add(tn);
            aa = aa.multiply(ten);
        }

        System.out.println("a+aa+aaa+...+aaa...(n个a) = " + sn);
    }
}

        输入a = 5 , n = 1000,看运行结果:

         也许,生活中用不到那么大的数,但在科学计算中,其还是有一定作用的。

八:

        求以下和式的值:     

          \sum_{n=1}^{20}n! 

        这题比较容易,实现如下:


/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote  Java练习八:
 *           求∑n!, n从1到20, (即求 1! + 2! + 3! + ... + 20!)
 */
public class Question18 {
    public static void main(String[] args) {
        // 求和结果可能大于long类型的最大值2^63-1,此处改用声明为float(38位),或者double(300多位)
        float s = 0, t =1;
        int n;
        for (n = 1; n <= 20; n++) {
            t *= n;   // 求 n!
            s += t;   // 累加
        }

        System.out.println("1!+2!+3!+...+20!=" + s);
    }
}

         运行结果如下:

    

九:

        输出所有的“水仙花数“。

        所谓“水仙花数”是指一个3位数 , 其各位数字的立方和等于该数本身,

        例如,153是一水仙花数,因为 $$153=1^3+5^3+3^3  。   

        关键在于获取这个3位数的各个位上的数字: 


/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote  Java练习九:
 *           输出所有的“水仙花数“。
 *           所谓“水仙花数”是指一个3位数,其各位数字的立方和等于该数本身,
 *           例如,153是一水仙花数,因为153 = 1^3 + 5^3 + 3^3
 */
public class Question19 {
    public static void main(String[] args) {
        int i,j,k,n;
        System.out.print("所有'水仙花数'为:");
        for(n = 100; n < 1000; n++){
            i = n / 100;  // 百位
            j = n / 10 - i * 10;  // 十位
            k = n % 10;  // 个位
            if(n == i * i *i + j * j * j + k * k * k){
                System.out.print(n);
                System.out.print(' ');
            }
        }
    }
}

        运行结果:

十:

        一个数如果恰好等于它的因子之和, 这个数就称为“完全数”,

        例如, 6的因子为1,2,3, 而6=1+2+3, 因此6是“完全数”,

        编程序找出1000之内的所有完全数,

        并按下面格式输出其因子:   6, its factors are 1,2,3 

        关键在于如何找出一个数的因子: 


/**
 *
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote  Java练习十:
 *           一个数如果恰好等于它的因子之和, 这个数就称为“完数”,
 *           例如,6的因子为1,2,3, 而6=1+2+3,因此6是“完数”,
 *           编程序找出1000之内的所有完数,并按下面格式输出其因子:
 *           6, its factors are 1,2,3
 *
 */
public class Question20 {
    public static void main(String[] args) {
        int m, s, i;
        for (m = 2; m <= 1000; m++) {
            s = 0;
            for (i = 1; i < m; i++) {
                if ((m % i) == 0) {
                    // 因子的和
                    s = s + i;
                }
            }
            if (s == m) {
                System.out.print(m + ",its factors are:");
                for (i = 1; i < m; i++) {
                    if (m % i == 0) {
                        System.out.print(i);
                        System.out.print(',');
                    }
                }
                // 换行输出下一个完全数
                System.out.println();
            }

        }

    }
}

             运行结果:

十一:

        有一分数序列

        $$\frac{1}{2},\quad\frac{3}{2},\quad\frac{5}{3},\quad\frac{8}{5},\quad\frac{13}{5},\quad\frac{18}{13}\quad......

        求出这个数列的前20项之和。

        找规律:

        1. 前一项分子分母之和为下一项的分子,
        2. 前一项的分子作为下一项的分母。

        实现如下:


/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习十一:
 *          有一分数序列
 *          2/1, 3/2, 5/3, 8/5, 13/8, 21/13
 *          出这个数列的前20项之和
 *
 *
 * 求
 */
public class Question21 {
    public static void main(String[] args) {
        int i, t;
        double a = 2, b = 1, s = 0;
        for (i = 0; i < 20; i++) {
            s += (a/b);
            t = (int) a;
            // 前一项分子分母之和为下一项的分子
            a = a + b;
            // 前一项的分子作为下一项的分母
            b = t;
        }

        System.out.println("2/1+3/2+5/3+8/5+...(20项) = " + s);
    }
}

         运行结果:

十二:

        猴子吃桃问题。

        猴子第1天摘下若干个桃子, 当即吃了一半, 还不过瘾, 又多吃了一个,

        第2天早上又将剩下的桃子吃掉一半,又多吃了一个,

        以后每天早上都吃了前一天剩下的一半另加一个,

        到第10天早上想再吃时,就只剩一个桃子了,

        求第1天共摘了多少个桃子。 

        显然,我们只能从第10天往前推:

        第K天的桃子数 = ( 第K+1天桃子数 + 1 ) *  2


/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote Java练习十二:
 *          猴子吃桃问题。
 *          猴子第1天摘下若干个桃子, 当即吃了一半, 还不过瘾, 又多吃了一个,
 *          第2天早上又将剩下的桃子吃掉一半,又多吃了一个,
 *          以后每天早上都吃了前一天剩下的一半另加一个,
 *          到第10天早上想再吃时,就只剩一个桃子了,
 *          求第1天共摘了多少个桃子。
 */

public class Question22 {
    public static void main(String[] args) {
        int day,x1 = 0,x2;
        day = 9;
        x2 = 1;
        // 迭代
        while(day > 0){
            x1 = (x2 + 1) * 2;
            x2 = x1;
            day--;
        }
        System.out.println("猴子第一天共摘了" + x1 + "个桃子。");
    }
}

        运行结果:

十三:

        用迭代法求  $$x=\sqrt{a} ,

        迭代公式为:$$x_{n+1}=\frac{1}{2}\left(x_n +\frac{a}{x_n} \right ) ,  

        要求:前后两次求出的x的差的绝对值小于  $$10^{-5}    

     (......不知道为什么使用LaTex产生的数学式子,会往上偏一点😅  )

         此题难点在于递推公式如何使用:

   思路:

        1. 设定一个x的初值x0;

        2. 用以上递推公式求出x的下一个值x1;

        3. 再将x1代入右边,求出x2

        4. 如此继续下去,直到前后两次的x差值小于1e-5  

        实现如下:


import java.util.Scanner;

/**
 * @author sixibiheye
 * @date 2021/10/13
 * @apiNote  Java练习十三:
 *           用迭代法求 x = √a (根号a),迭代公式为:
 *           x(n+1) = 0.5*(x(n) + a/x(n))
 *           要求:前后两次求出的x的差的绝对值小于1e-5
 *
 *           思路:
 *           1. 设定一个x的初值x0;
 *           2. 用以上递推公式求出x的下一个值x1;
 *           3. 再将x1代入右边,求出x2
 *           4. 如此继续下去,直到前后两次的x差值小于1e-5
 */
public class Question23 {
    public static void main(String[] args) {
        System.out.print("请输入一个正整数:");
        Scanner scanner = new Scanner(System.in);
        float a = scanner.nextFloat();
        float x0 = a / 2;
        //计算左边的x
        float x1 = (x0 + a / x0) / 2;
        // 至少计算一次,此处用do...while循环
        do {
            x0 = x1;
            x1 = (x0 + a / x0) / 2;
        } while (Math.abs(x1 - x0) > 1e-5);
        System.out.println(a + "的算术平方根为:" + x1 + '。');

    }
}

        运行结果: 

         

        好啦~今天的练习就分享到这了,虽然挺基础的几个练习,但也有着许多我们曾忽略过的东西,希望大家看完之后都有所收获。最后,喜欢的小伙伴们点个赞鼓励支持一下吧~ 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易果啥笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值