JavaSE综合练习学习记录

练习一:飞机票

需求

  • 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
  • 按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。
package Test;

import java.util.Scanner;

public class Test01 {
    public static void main(String[] args) {
        // 输入机票价格、飞行时间、
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入原价机票");
        double price = sc.nextInt();
        System.out.println("请输入出行月份");
        int month = sc.nextInt();
        System.out.println("请输入机舱型号:");
        System.out.println("1,头等舱;2,经济舱");
        int model = sc.nextInt();

        // 判断输入是否有问题
        if (month>0 && month<=12 && (model==1 || model==2 )) {
            double preferential = calculate(price, month, model);  // 优惠后的价格
            System.out.println("优惠后的价格是:" + preferential);
        }else {
            System.out.println("输入有问题,请检查后重重输入!");
        }

    }

    // 判断月份方法
    public static double calculate(double price, int month, int model) {
        double preferential = 0;
        switch (month){
            case 5, 6, 7, 8, 9, 10:{  // 旺季
                if (model == 1){  // 头等舱
                    preferential = price * 0.9;  // 打9折
                }else {  // 经济舱
                    preferential = price * 0.85;  // 打8.5折
                }
                break;
            }
            case 1, 2, 3, 4, 11, 12 :{  // 淡季
                if (model == 1){  // 头等舱
                    preferential = price * 0.7;  // 7折
                }else {  // 经济舱
                    preferential = price * 0.65;  // 6.5折
                }
                break;
            }
        }
        return preferential;

    }
}

首先是要从键盘获取输入,这个没得说。

之后要对用户的输入做一个判断,如果给一个错误的数,那么整个程序就会崩溃。

然后我写了个方法,或者机票优惠后的价格,

判断淡季旺季,我用到了switch,为什么不用if ,老师用的是if。我感觉月份还是很容易确定这个范围的,if的话,大于小于我容易搞混是。

之后就是求价格。

练习二:打印素数

判断101~200之间有多少个素数,并输出所有素数。

备注:素数就是质数

package Test;

public class Test02 {
    public static void main(String[] args) {
        int count=0;
        // 判断101~200之间多少个素数
        for (int i = 101; i <= 200; i++) {
            boolean sign = true;
            // 判断是否可以被其他数整除
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    sign = false;
                    break;
                }
            }
            // 质数统计
            if (sign){
                System.out.println(i + "是质数");
                count++;
            }
        }
        System.out.println("一共有" + count + "个质数");
    }
}

之前学习过怎么判断一个数是不是质数,而这个是怎么判断这堆数里面有哪些质数。

如果内循环可以看明白,外循环也是不难,就是生成多个数。

最后用if做一个统计,就出来了。

练习三:验证码

需求

  • 定义方法实现随机产生一个5位的验证码

验证码格式:

  • 长度为5
  • 前四位是大写字母或者小写字母
  • 最后一位是数字
package Test;

import java.util.Random;

public class Test03 {
    public static void main(String[] args) {
        Random r = new Random();  // 随机数
        char[] letterArr = new char[52];  // 存放字母
        int arrIndex=0;  // 为索引
        String result = "";  // 字符串变量,存放生成的验证码

        // 对数组进行赋值
        for (int i = 65; i <=122 ; i++) {
            // 特殊字符处理。
            if(i==91 || i==92 || i==93 || i==94 || i==95 || i==96){
                continue;
            }
            letterArr[arrIndex] = (char) (i);
            arrIndex++;
        }

        // 验证码生成
        for (int i = 1; i <= 4; i++) {
            int randomIndex = r.nextInt(52);
            result += letterArr[randomIndex];  // 字母部分
        }
        result += r.nextInt(10);  // 数字部分
        System.out.println(result);
    }
}

验证码是随机的,那肯定要用到随机数方法。

我一开始是想着创建一个存放验证码的数组。但是这个数组该是什么类型呢,因为这个验证码是由字母+数字组成的。

然后老师点拨了一下

在以后如果我们要在一堆没有什么规律的数字中随机抽取,可以先把这些数组放到当中,在随机一个索引。

所有我动态创建了一个字符型数组letterArr

但是怎么存放字母呢?之前学习过强制类型转换,然后我又知道字母的ASCII码,所以一激灵写了个循环。

// 对数组进行赋值
for (int i = 65; i <=122 ; i++) {
	
}

循环的开始是65,结束是122,这个也是有讲究的。从A ~z 的ASCII码就是65~122。

数据存进去后,我又发现了不对的地方。

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z    

中间有一部分是我不想要的,当时,我也是把数组开大了,长度52我故意写的55

然后我又通过查询ASCII码发现了问题65~122中间还有一些不需要的字符。

准确的说大写字母A~Z 的ASCII码是65~90 、小写字母a~z 的ASCII码是97~122

从91~96是不需要的。

if(i==91 || i==92 || i==93 || i==94 || i==95 || i==96){
	continue;
}

然后用一个伪索引。

就这样数据准备好了,但是老师是这么写的。

 // 对数组进行赋值
for (int i = 0; i < letterArr.length ; i++) {
	if (i<=25){
    	letterArr[i] = (char) (97 + i); // 小写字母
    }else {
    	letterArr[i] = (char) (65 + i - 26);  // 大写字母
    }
}

现在就是怎么对数据抽取了。随机索引。

我一开始是这么写的

// 验证码生成
for (int i = 1; i <= 4; i++) {
	int temp = r.nextInt(52);
    System.out.print(letterArr[temp]);  // 字母部分
}
System.out.print(r.nextInt(10));  // 数字部分

老师是直接在上面定义了一个字符串。String result = ""; 这是我没有想到的地方。

然后改了一下,

// 验证码生成
for (int i = 1; i <= 4; i++) {
	int randomIndex = r.nextInt(52);
    result += letterArr[randomIndex];  // 字母部分
}
result += r.nextInt(10);  // 数字部分
System.out.println(result);

完成了。

练习四:复制数组

需求

  • 把一个数组中的元素复制到另一个新数组中去。
package Test;

public class Test04 {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55};  // 定义一个数组
        int[] newArr = copyArr(arr);
        System.out.println("arr数组地址:"+ arr);  // arr数组地址:[I@6d311334
        System.out.println("nweArr数组地址:"+ newArr);  // nweArr数组地址:[I@568db2f2
        for (int i = 0; i < newArr.length; i++) {
            System.out.print(newArr[i] + " ");
        }
    }

    // 数组复制方法
    public static int[] copyArr(int[] arr) {
        int[] newArr = new int[arr.length];
        for (int i = 0; i < newArr.length; i++) {
            newArr[i] = arr[i];  // 数组元素复制
        }
        return newArr;
    }

    public static char[] copyArr(char[] arr) {
        char[] newArr = new char[arr.length];
        for (int i = 0; i < newArr.length; i++) {
            newArr[i] = arr[i];  // 数组元素复制
        }
        return newArr;
    }

    public static double[] copyArr(double[] arr) {
        double[] newArr = new double[arr.length];
        for (int i = 0; i < newArr.length; i++) {
            newArr[i] = arr[i];  // 数组元素复制
        }
        return newArr;
    }

}

这个很简单,数组元素的赋值,但注意不可以直接把数组赋值给新数组

int[] arr = {11, 22, 33}
int[] arr2 = arr; 

不可以。

然后我根据方法的重载,有些了几个方法,有时候有可能复制的字符数组呢。

练习五:评委打分

需求

  • 在唱歌比赛中,有6名评委给选手打分,分数范围是[0 - 100]之间的整数。选手的最后得分为:去掉最高分、最低分后的4个评委的平均分,请完成上述过程并计算出选手的得分。
package Test;

import java.util.Scanner;

public class Test05 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);  // 需要输入成绩
        int[] scoreArr = new int[6];  // 存储成绩
        double sum=0, avg=0;  // 求和、求平均

        // 往数组里面输入成绩
        for (int i = 0; i < scoreArr.length;) {
            System.out.print("请第"+ (i+1)+ "号评委打分:");
            int temp = sc.nextInt();
            // 判断数据是否符合
            if (temp>=0 && temp<=100){
                scoreArr[i] = temp;
                i++;
            }else {
                System.out.println("成绩输入有误");
            }
        }

        sortArr(scoreArr);  // 对评分进行排序

        // 统计(不含第一个元素[0]和最后一个元素[5])
        for (int i = 1; i < scoreArr.length-1; i++) {
            sum += scoreArr[i];
        }
        avg = sum / (scoreArr.length-2);  // 求平均
        System.out.println(avg);
    }

    // 冒泡排序方法
    public static int[] sortArr(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            // 内循环,控制次
            for (int j = 0; j < arr.length - 1 - i; j++) {
                // 比较相邻的两个元素
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;
    }
}

输入成绩,然后对成绩是否符合规范做判断,注意第一个问题,就是i++ 在里面的问题。

判断数据是否符合,如果不符合那么i 不计数。数据不存储到数组,因此就实现了评委打分错误可以重复大分

请第1号评委打分:111
成绩输入有误
请第1号评委打分:111
成绩输入有误
请第1号评委打分:111
成绩输入有误
请第1号评委打分:100

然后用到了我之前写的冒泡排序,对这个数组进行排序,就可以知道最小的元素索引是[0]、最大的是[5]

这里注意一个问题,他有返回值,但是我没有赋值

// 对评分进行排序
int[] sortNewArr = sortArr(scoreArr);  // 应该是这样。 
sortArr(scoreArr);  // 我写的

这两种方式都可以实现,我说一下的写法,

其实这两个数组共用一块内存。所以数组就改变了。

然后求和,求平均、求和时不带最小值[0] 和最大值scoreArr.length-1

最大元素怎么判断,六个元素最大索引是5、7个元素最大索引是6、8个元素最大索引是7、那就是数组长度减一。scoreArr.length-

练习六:数字加密

需求:

  • 某系统的数字密码(大于0),比如1983,采用加密方式进行传输。

规则如下:

  • 先得到每位数,然后每位数都加上5 , 再对10求余,最后将所有数字反转,得到一串新数。

举例:

		1	9	8	3
+5		6   14  13  8
%10		6   4   3   8
反转	   8   3   4   6
加密后的结果就是:8346
package Test;

import java.util.Scanner;

public class Test06 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入需要加密的密码:");
        int password = sc.nextInt();  // 获取密码
        int len = getLen(password);  // 密码长度
        int[] passArr = new int[len];  // 存放拆分后的密码
        int index = 0;

        // 密码拆分
        while (password != 0) {
            int t = password % 10;
            passArr[index] = t;  // 自动实现反转
            password /= 10;
            index++;
        }

        // 数字加密
        for (int i = 0; i < passArr.length; i++) {
            passArr[i] = (passArr[i] + 5) % 10;  // 先+5, 再%10
            System.out.print(passArr[i]);
        }
    }

    // 返回密码长度(数位)
    public static int getLen(int number) {
        int count=0;  // 计数器
        while (number != 0){
            number /= 10;
            count++;
        }
        return count;
    }
}

一开始,我以为这是一个算法题,不是,

首先需要输入密码,

因为是要对密码的每一位数字进行操作,所以最好的方式就是把密码的每一位数字放进数组里面。这里又有一个问题就是密码的长度不是我定的,而是用户定的。所以数组的长度不能确定。

因此我写了个ggetLen 方法。获取这个密码长度,然后创建数组passArr 。数组的长度就是int len

接下来就是考虑怎么把密码分别放进数组了。

// 密码拆分
int index = 0;
while (password != 0) {
    int t = password % 10;
    passArr[index] = t;  // 自动实现反转
    password /= 10;
	index++;
}

其实一开始我是这么想着。

// 密码拆分
int index = 3;
while (password != 0) {
    int t = password % 10;
    passArr[index] = t;  // 自动实现反转
    password /= 10;
	index--;
}

比如我随便给一个数字1234,然后数位拆分后是4 3 2 1。我想这是数组的存放顺序应该是{1,2,3,4} 所以设置伪索引为4.

passArr[3] = 4; 
passArr[2] = 3; 
passArr[1] = 3; 
passArr[0] = i;
// {1,2,3,4}

既然拆分后是倒的,那我也倒的存。看着是没有问题了,但是又是一个问题的开始,密码的最后一步还要你反转过来,1234要反转过来 4321 。数组怎么反转呢?我左思右想,想到了之前本来就是倒过来的,(密码拆分那一步1234 拆分后就是4 3 2 1

然后就改回来了。让伪索引从9开始

// 密码拆分
int index = 0;
while (password != 0) {  // 1234
    int t = password % 10;  // 4 3 2 1
    passArr[index] = t;  // 自动实现反转
    password /= 10;
	index++;
}

加密密码没什么可说的,按照要求。

之后输出。

但是老师是这么输出的。

//3.把数组里面的每一个数字进行拼接,变成加密之后的结果
int number = 0;
for (int i = 0; i < arr.length; i++) {
	number = number * 10 + arr[i];
    }
System.out.println(number);

假设数组arr = {1, 2, 3, 4}

第1次循环,number = 0*10+1 = 0+1number=1a[0] = 1

第2次循环,number = 1*10+2 = 10+2number=12 ;a[0] = 2`

第3次循环,number = 12*10+3 = 120+3number=123a[0] = 3

第4次循环,number = 123*10+4 = 1230 + 4number=1234a[0] = 5

System.out.println(number);1234

还有,老师实现了数组反转

//将所有数字反转
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
    int temp = arr[i];
    arr[i] = arr[j];
	arr[j] = temp;
}

老师用了两个索引,i 从头开始;j 从尾开始。一次操作

i = 0; j = 4 arr[0] <--> arr[4]

i = 1; j = 3 arr[1] <--> arr[3]

而我是在密码拆分中自动反转了。

练习七:数字解密

把上一题加密之后的数据进行解密

package Test;

import java.util.Scanner;

public class Test07 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入需要解密的四位数密码:");
        int password = sc.nextInt();  // 获取密码
        int len = getLen(password);  // 密码长度
        int[] passArr = new int[len];  // 存放拆分后的密码
        int index=0;

        // 密码拆分
        while (password != 0) {
            int t = password % 10;
            passArr[index] = t;  // 反转存储实现
            password /= 10;
            index++;
        }

        // 数字解密
        for (int i = 0; i < passArr.length; i++) {
            if (passArr[i]>=0 && passArr[i]<=4){
                passArr[i] = passArr[i]+10-5;  //
            }else {
                passArr[i] = passArr[i]-5;
            }
            System.out.print(passArr[i]);
        }
    }

    // 返回密码长度(数位)
    public static int getLen(int number) {
        int count=0;  // 计数器
        while (number != 0){
            number /= 10;
            count++;
        }
        return count;
    }
}

和加密的代码一致,只不过加密和解密的算法不一样。

我们说加密是先+5 %10。现在把他们反过来就行+5变成-5。这个%10我想了半天,其实不难。

假设我们解密这堆数:8346

先是反转,6438。(加密的最后一步是反转,那么解密也需要反转)

之后就要思考,?%10=6?%10=4

6%10=616%10=626%10=636%10=646%10=6、…

那应该是哪一个呢,很显然是6

其实有这么一段规律,或者是范围

什么意思呢,

就说+5 这件事,再给数字加密的时候,需要+5,最小值是0+5=5 、最大值是9+5=14

还是要说一会加密。

	1	9	8	3
+5	6   14  13  8

就是说对密码加密后的结果是有一个范围的,最小值是0+5=5 、最大值是9+5=14。因为需要加密的密码中没有0,如果有0,那么0+5=5,是符合规则的。

得知在对加密的数字进行+5得到的数字是有范围在5~14 之间的。

那么再看这堆:6%10=616%10=626%10=636%10=646%10=6、…

16、26、36…是已经超出范围的,之间pass。

密码0123456789
+5567891011121214
%105678901234

然后就可以通过表格发现如果取余后的数字(需要解密的数字)在5~9这个范围,那么取余前的数字与取余后的数字相等、一致。

如果在10~14之间,那么取余前 = 取余后+10

因此就解决了,加密有个+5的过程,那么取余就是-5

假设密码是3,那么3+5=88%10=8 ,加密是8;对8 解密,因为(8>5 && 8<9)8=88-5=3 , 解密是3

假设密码是7,那么7+5=1212%10=2,加密是2;对2 解密,因为(2>0 && 2<4)2+10=1212-5=7 , 解密是7

// 数字解密
for (int i = 0; i < passArr.length; i++) {
	if (passArr[i]>=0 && passArr[i]<=4){
    	passArr[i] = passArr[i]+10-5;  
        }else {
        	passArr[i] = passArr[i]-5;
		}
	System.out.print(passArr[i]);
}

加密、解密,可以测试一下

测试1:
	请输入需要加密的密码:1314
	加密后的密码是:9686	
	请输入需要解密的四位数密码:9686
	解密后的密码是:1314
测试二:
    请输入需要加密的密码:8520
    加密后的密码是:5703
    请输入需要解密的四位数密码:5703
    解密后的密码是:8520
测试三:
    请输入需要加密的密码:2022
    加密后的密码是:7757
    请输入需要解密的四位数密码:7757
    解密后的密码是:2022
测试四:
    请输入需要加密的密码:123456
    加密后的密码是:109876
    请输入需要解密的四位数密码:109876
    解密后的密码是:123456
测试五:
    请输入需要加密的密码:123456789
    加密后的密码是:432109876
    请输入需要解密的四位数密码:432109876
    解密后的密码是:123456789

没有翻车

练习八:抽奖

需求:

  • 一个大V直播抽奖,奖品是现金红包,分别有{2, 588 , 888, 1000, 10000}五个奖金。请使用代码模拟抽奖,打印出每个奖项,奖项的出现顺序要随机且不重复。打印效果如下:(随机顺序,不一定是下面的顺序)
888元的奖金被抽出
588元的奖金被抽出
10000元的奖金被抽出
1000元的奖金被抽出
2元的奖金被抽出

解法一

package Test;

import java.util.Random;

public class Test08 {
    public static void main(String[] args) {
        int[] bonusArr = {2, 588 , 888, 1000, 10000};  // 现金红包
        int[] extractArr = new int[5];  // 存放抽取的奖金
        Random r = new Random();

        // 模拟抽奖, 对bonusArr里面的奖项抽奖
        for(int i =0; i<bonusArr.length;){
            int randomIndex = r.nextInt(5);
            if (!existArr(extractArr, bonusArr[randomIndex])) {
                extractArr[i] = bonusArr[randomIndex];
                i++;
            }
        }

        // 打印抽奖结果
        for (int i = 0; i < extractArr.length; i++) {
            System.out.println(extractArr[i] + "元的奖金被抽出");
        }

    }

        // 判断元素是否在数组中存在
        public static boolean existArr(int[] arr, int num) {
        for (int i = 0; i < arr.length; i++) {
            if(num == arr[i]){
                return true;
            }
        }
        return false;
    }
}

这道题很简单。要考虑清楚一件事就可以,创建一个随机索引,因为是不重复抽奖,而随机索引是必会有重复。那么就写一个方法,判断这个元素是否存在于数组。

// 判断元素是否在数组中存在
public static boolean existArr(int[] arr, int num) {
	for (int i = 0; i < arr.length; i++) {
    	if(num == arr[i]){
        	return true;  // 存在
		}
    }
	return false;  // 不存在
}

写起来也很简单,遍历数组每一个元素,如果有元素与这个数字相等,那么存在,如果执行完,没有一个相等的,那么不存在。

然后就是模拟抽奖

// 模拟抽奖, 对bonusArr里面的奖项抽奖
for(int i =0; i<bonusArr.length;){
	int randomIndex = r.nextInt(5);
    // 不存在,false,取反!false
    if (!existArr(extractArr, bonusArr[randomIndex])) {
    	extractArr[i] = bonusArr[randomIndex];
        i++;
    }
}

抽取五次,每一次抽取都会随机一个索引,然后得到一个元素。

接下来,就是判断这个元素是否已经存在在extractArr 数组里面。

if (!existArr(extractArr, bonusArr[randomIndex])) {
	extractArr[i] = bonusArr[randomIndex];
    i++;
}

这里有个取反的逻辑需要清楚,

如果元素存在数组extractArr中,那么返回true ;不存在,返回false

但是if 语句的条件只有为true 才能执行。

但是true 的话,那就是存在,显然问题不对,所以对false 取反!false, 那就是true

既然不存在,那就添加,然后i++

这道题也就写出来了。

解法二

package Test;

import java.util.Random;

public class Test08_2 {
    public static void main(String[] args) {
        int[] bonusArr = {2, 588 , 888, 1000, 10000};  // 现金红包
        randomArr(bonusArr);
        // 打印抽奖结果
        for (int i = 0; i < bonusArr.length; i++) {
            System.out.println(bonusArr[i] + "元的奖金被抽出");
        }
    }

    // 数组打乱
    public static int[] randomArr(int[] arr) {
        Random r = new Random();
        for (int i = 0; i < arr.length; i++) {
            int randomIndex = r.nextInt(arr.length);
            int temp = arr[i];
            arr[i] = arr[randomIndex];
            arr[randomIndex] = temp;
        }
        return arr;
    }
}

解法一,比较拉分时间,因为第一次抽奖的奖项是不可能有重复的,其他的都有判断,费时间

而现在的揭发而直接打乱数组就可以了。

随机一个索引,与i索引进行交换就可以了。可以说这个五次循环就可以了。

上的解法一起码有五五二十五次循环。

练习九:双色球

image
package Test;

import java.util.Random;
import java.util.Scanner;

public class Test09 {
    public static void main(String[] args) {
        int redCount=0; // 红球中奖情况
        int blueCount=0; // 蓝球中奖情况

        // 1, 生成中间号码
        int[] numberArr = createNum();
//        System.out.println("============");
//        for (int i = 0; i < numberArr.length; i++) {
//            System.out.print(numberArr[i] + " ");
//        }
//        System.out.println();
//        System.out.println("============");

        // 2, 用户输入彩票号码
        int[] inputArr = inputNumber();

        // 3, 判断中奖情况
        // 判断红球
        for (int i = 0; i < 6; i++) {
            int redNumber = inputArr[i];  // 产生一个红球
            for (int j = 0; j < 6; j++) {
                if (redNumber == numberArr[j]){
                    redCount++;
                    break;
                }
            }
        }
        // 判断蓝球
        if (inputArr[6] == numberArr[6]){
            blueCount++;
        }

        // 4, 整理输出
        String str = situation(redCount, blueCount);  // 中奖情况统计
        print(numberArr, inputArr, redCount, blueCount, str);
    }

    //内容输出
    public static void print(int[] numberArr, int[] inputArr, int redCount, int blueCount, String result) {
        System.out.println("=================================");
        System.out.print("本期号码:");
        for (int i = 0; i < numberArr.length; i++) {
            System.out.print(numberArr[i] + " ");
        }
        System.out.println();
        System.out.print("您的号码:");
        for (int i = 0; i < inputArr.length; i++) {
            System.out.print(inputArr[i] + " ");
        }
        System.out.println();

        System.out.println("红球:" + redCount);
        System.out.println("蓝球:" + blueCount);
        System.out.println("本期中奖情况:" + result);
        System.out.println("=================================");
    }

    // 用户输入彩票号码
    public static int[] inputNumber() {
        System.out.println("欢迎使用双色球系统!");
        int[] numArr = new int[7];  // 7个球
        Scanner sc = new Scanner(System.in);

        // 输入红色球号码
        for (int i = 0; i < 6; ) {
            System.out.print("请输入第" + (i+1) + "个红色球:");
            int redNumber = sc.nextInt();
            if (redNumber>=1 && redNumber <= 33){
                if (!existArr(numArr, redNumber)) {
                    numArr[i] = redNumber;
                    i++;
                }else {
                    System.out.println("当前红色球已存在,请重新输入!");
                }
            }else {
                System.out.println("超出红色球号码范围(1~33),请重新输入!");
            }
        }

        // 输入蓝色球号码
        System.out.print("请输入1个蓝色球:");
        while (true){
            int blueNumber = sc.nextInt();
            if (blueNumber>=1  && blueNumber<=16 ){
                numArr[6] = blueNumber;
                break;
            }else{
                System.out.println("超出蓝色球号码范围(1~16),请重新输入!");
            }
        }

        return numArr;
    }

    // 判断中奖情况
    public static String situation (int redNumber, int blueNumber) {
        String str = "";  // 字符串变量
        if (redNumber==6 && blueNumber==1){
            str = "一等奖,最高1000万";
        }else if (redNumber==6 && blueNumber==0){
            str = "二等奖,最高500万";
        }else if (redNumber==5 && blueNumber==1) {
            str = "三等奖,3000元";
        }else if ((redNumber==5 && blueNumber==0) || (redNumber==4 && blueNumber==1)) {
            str = "四等奖,200元";
        }else if ((redNumber==4 && blueNumber==0) || (redNumber==3 && blueNumber==1)) {
            str = "五等奖,10元";
        }else if ((redNumber==2 && blueNumber==1) || (redNumber==1 && blueNumber==1) || (redNumber==0 && blueNumber==1)){
            str = "五等奖,5元";
        }else {
            str = "谢谢参与";
        }
        return str;
    }


    // 随机生成一组中奖号码
    public static int[] createNum() {
        // 6个红色球,1个蓝色球,长度为7
        int[] numArr = new int[7];
        Random r = new Random();

        // 随机生成6个红球
        for(int i = 0; i <= 6;){
            int redNumber = r.nextInt(33) + 1;
            // 号码不能重复
            if (!existArr(numArr, redNumber)){
                numArr[i] = redNumber;  // 不重复,添加该元素
                i++;
            }
        }

        // 随机生成1个蓝球
        numArr[6] = r.nextInt(16) + 1;

        return numArr;
    }

    // 判断元素是否在数组中存在
    public static boolean existArr(int[] arr, int num) {
        for (int i = 0; i < arr.length; i++) {
            if(num == arr[i]){
                return true;
            }
        }
        return false;
    }

}

这道题是我想难了。其实不难,就是对两个数组里的元素进行统计,然后再判断就可以了。

一开始我没有明白,因为我从来没有关注过双色球。

现在我说一下双色球的规则,六个红球,一个蓝球一共七个球。

然后根据你买的彩票号码一位一位跟这一期的号码进行比对。最后看红球对了多少个,蓝球对了多少个。

比如

本期号码是11 14 15 29 25 7 9

我的号码是11 25 17 32 12 15 9

然后就开始对比,看看11有没有出现在本期号码中、25 有没有、17 有没有…;再看最后一位蓝球是不是相同,

最后发现红球中112515 这三个号码与本期号码相同,蓝球也是99 一样

得出结果,红球中了3个,蓝球中了1个。五等奖,10元。

接下来说代码实现,咱们就来分析主方法就可以。

public static void main(String[] args) {
	int redCount=0; // 红球中奖情况
    int blueCount=0; // 蓝球中奖情况

    // 1, 生成中间号码
    int[] numberArr = createNum();
    
    // 2, 用户输入彩票号码
    int[] inputArr = inputNumber();

    // 3, 判断中奖情况
    // 判断红球
    for (int i = 0; i < 6; i++) {
    	int redNumber = inputArr[i];  // 产生一个红球
        for (int j = 0; j < 6; j++) {
        	if (redNumber == numberArr[j]){
            	redCount++;
                break;
			}
		}
    }
    // 判断蓝球
	if (inputArr[6] == numberArr[6]){
    	blueCount++;
    }

    // 4, 整理输出
    String str = situation(redCount, blueCount);  // 中奖情况统计
	print(numberArr, inputArr, redCount, blueCount, str);
}

首先是要生成一个中奖号码,那我就定义一个方法createNum()

createNum()方法里面,先定义了一个数组,数组长度是6个红球+1个蓝球=7

红球的范围1~33;蓝球1~16

然后就随机往里面进行存放数字,

int redNumber = r.nextInt(33) + 1;

我一直在想为什么要+1, 因为r.nextInt(33)的范围是从0~32刚好包含了0,没有包含33。而红球的范围是1~33所以+1就解决了。

比如,随机了一个数0,那么0+1正好符合,32+1也是这样。

然后呢数组元素不可以重复,那我就把上一题的判断元素是否重复的代码复制过来existArr()

就这样可以随机生成一个本期开奖号码。

让用户自己输入自己的彩票号码,这里用到了嵌套判断,其实逻辑都很简单,看看有没有重复,看看有没有超出范围,提示一下,重新输入。这里没有什么可说的。

然后就是判断用户的中奖情况。

// 3, 判断中奖情况
// 判断红球
for (int i = 0; i < 6; i++) {
	int redNumber = inputArr[i];  // 产生一个红球
    for (int j = 0; j < 6; j++) {
    	if (redNumber == numberArr[j]){
        	redCount++;
            break;
         }
    }
}

// 判断蓝球
if (inputArr[6] == numberArr[6]){
	blueCount++;
}

判断中奖情况是由一个规则的,那就是红球和红球判断,蓝球和蓝球。

此时这个数组里面,前六个是红球,后一个是蓝球。是由红球的索引范围是[0]~[5] ;蓝球[6]

所以生成一个循环框架

for (int i = 0; i < 6; i++) {
   for (int j = 0; j < 6; j++) {
       
	}
}

首先在inputArr[i]产生一个红球redNumber ,然后再在numberArr 数组里面判断是否存在,存在,红球+1

此时注意,判断一个元素是否在数组中存在是有一个方法的existArr()。我们之前写的方法,但是为什么不用呢。

注意判断中奖规则的索引不一样,是不一样的,existArr()方法的索引是从数组的开始到结尾,而判断中奖情况是从头到倒数第二个元素,蓝球单独判断

// 判断中奖情况
for (int i = 0; i < 6; i++) {  

}

// existArr方法
for (int i = 0; i < arr.length; i++) {
      
}

注意不要忘了判断蓝球

// 判断蓝球
if (inputArr[6] == numberArr[6]){
	blueCount++;
}

至此,就写完大部分了,然后接下来就是对这个结果进行统计,我写了个situation() 方法。

然后就是输出结果print()

欢迎使用双色球系统!
请输入第1个红色球:12
请输入第2个红色球:10
请输入第3个红色球:16
请输入第4个红色球:25
请输入第5个红色球:27
请输入第6个红色球:31
请输入1个蓝色球:9
=================================
本期号码:18 30 23 5 31 4 11 
您的号码:12 10 16 25 27 31 9 
红球:1
蓝球:0
本期中奖情况:谢谢参与
=================================

进程已结束,退出代码为 0

没中奖!

============
7 3 13 4 10 18 7 
============
欢迎使用双色球系统!
请输入第1个红色球:4
请输入第2个红色球:13
请输入第3个红色球:7
请输入第4个红色球:18
请输入第5个红色球:3
请输入第6个红色球:10
请输入1个蓝色球:7
=================================
本期号码:7 3 13 4 10 18 7 
您的号码:4 13 7 18 3 10 7 
红球:6
蓝球:1
本期中奖情况:一等奖,最高1000万
=================================

进程已结束,退出代码为 0

测试代码

但我看有人说老师说的双色球规则不对。先这样不管了。

练习十:万年历

输入年、月;输出当前月日历

package Test;

import java.util.Scanner;

public class Test10 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int year, month;  // 年、月
        int dw, days;  // 星期几、天数
        // 1, 输入年份、月份
        System.out.print("请输入查询年份:");
        year = sc.nextInt();
        System.out.print("请输入查询月份:");
        month = sc.nextInt();
        // 2,判断数据是否符合
        if (month>0 && month<=12){
            // 3, 计算月1日从星期几开始(dw)、这月有多少天(days)
            dw = weekDay(year, month);
            days = monthDays(year, month);
            // 4,
            printCalendar(year, month, dw, days);  // 打印日历

        }

    }

    // 计数1号是星期几
    public static int weekDay(int year, int month){
        int ww=2;  // 基准月,1980年1月1日是星期二
        int countDays=0;
        // 计算从1980年1月1日到year一共过了多少整年,一共多少天
        for (int i = 1980; i < year; i++) {
            countDays += 365 + isLeapYear(i);  // 一年365或者366
        }
        // 遍历1月1号到month一共过了多少整月,一共多少天
        for (int i = 1; i < month; i++) {
            countDays += monthDays(year, i);
        }
        return (ww + countDays)%7;
    }

    // 判断天数方法
    public static int monthDays(int year, int month) {
        int days=0;
        switch (month){
            case 1, 3, 5, 7, 8, 10, 12 -> days = 31;  // 31天
            case 4, 6, 9, 11-> days = 30;  // 30天
            case 2 -> days = 28 + isLeapYear(year);  // 平年28天,闰年29天
        }
        return days;
    }

    // 闰年、平平年判断
    public static int isLeapYear(int year) {
        if (year%4==0 && year%100!=0 || year%400==0){
            return 1;  // 闰年
        }else {
            return 0;  // 平年
        }
    }

    // 日历打印
    public static void printCalendar(int year, int month, int dw, int day) {
        // 打印标题
        System.out.println("========" + year + "年" + month + "月日历========");
        System.out.println("日" + "\t" + "一" + "\t" + "二" + "\t" + "三" + "\t" + "四" + "\t" + "五" + "\t" + "六");

        // 星期几开始,预留几个空格
        for (int i = 0; i < dw; i++) {
            System.out.print(" " + "\t");
        }

        // 打印每天
        for (int i = 1; i <= day; i++) {
            System.out.print(i + "\t");  // 不换行输出
            if ((i+dw)%7 == 0) {
                System.out.println();  // 换行
            }
        }
    }
}

把这个任务分开做,会容易一些,当时学习C语言、python时老师都让想过,那么Java也不例外。

当时做的时候老师分成了好几个阶段任务,而我直接做的,两三个小时做出来了。

虽然没有分任务,但是基本还是按着老师讲的步骤,还特意翻开了C语言万年历代,老师的教案。

先说考虑怎么打印一个日历。

 // 日历打印
 public static void printCalendar(int year, int month, int dw, int day) {
 	// 打印标题
    System.out.println("========" + year + "年" + month + "月日历========");
    System.out.println("日" + "\t" + "一" + "\t" + "二" + "\t" + "三" + "\t" + "四" + "\t" + "五" + "\t" + "六");

    // 星期几开始,预留几个空格
    for (int i = 0; i < dw; i++) {
    	System.out.print(" " + "\t");
    }

    // 打印每天
    for (int i = 1; i <= day; i++) {
    	System.out.print(i + "\t");  // 不换行输出
        if ((i+dw)%7 == 0) {
        	System.out.println();  // 换行
		}
	}
}

为了让日历美观,做个标题,也可以确定了每周的第一天从星期日开始。

为什么说是要打印空格呢。因为月1日不可能每一次都从星期日开始,如可能是从星期一开始,所以如果是从星期一开始,那么就要让出一个空格,星期二,两个;以此类推。

今年8月1号是星期一,那么留一个空格。

for (int i = 0; i < dw; i++) {
    	System.out.print(" " + "\t");
}

每一周从星期日开始,我们就设定星期日为0, 空格是到1日的前一天结束,所以i<dw

验证一下,比如这月1日是星期三,那么这一行从星期日到星期二全是空格,星期三开始就要显示日历。

再来说日历打印。如果单纯的写for循环,那么这就不是个日历,为什么,看下面代码

// 第一中。
for (int i = 1; i <= day; i++) {
	System.out.println(i);  // 不换行输出
}
/*
1
2
3
...
*/

// 第二种
for (int i = 1; i <= day; i++) {
	System.out.print(i + " ");  // 不换行输出
}
// 1 2 3 ...

很显然这不是个日历

日历应该是一行有七个数,一个月大概四周,四行

1	2	3	4	5	6	7	
8	9	10	11	12	13	14	
15	16	17	18	19	20	21	
22	23	24	25	26	27	28	
29	30	31	

所以就要考虑换行问题

// 打印每天
for (int i = 1; i <= day; i++) {
	System.out.print(i + "\t");  // 不换行输出
    if (i%7 == 0) {
    	System.out.println();  // 换行
    }
}

先把这一天输出,然后再判断,这一天要不要换行,换行的条件是什么,那必然是这一周过完了。七天一周,所以当i%7==0这周过完了,换行,注意是先输出在考虑要不要换行。

我一开始写成这样了、

// 打印每天
for (int i = 1; i <= day; i++) {
    if (i%7 == 0) {
    	System.out.println();  // 换行
    }
	System.out.print(i + "\t");  // 不换行输出
}

那么就是先考虑要不要换行,在输出。

1	2	3	4	5	6	
7	8	9	10	11	12	13	
14	15	16	17	18	19	20	
21	22	23	24	25	26	27	
28	29	30	31	

看着没问题,可是第一周的7呢?

因为他是先判断7%7==0所以换行,然后是再输出7,

应该是先输出7,再考虑换行。

接着回归到代码这一部分,

if ((i+dw)%7 == 0) {
	System.out.println();  // 换行
}

dw是空格,1日前面有几个空格。但是这几个空格也是占一天的呀,如果不管空格,会这样

 	1	2	3	4	5	6	7	
8	9	10	11	12	13	14	
15	16	17	18	19	20	21	
22	23	24	25	26	27	28	
29	30	31	

这个7为什么要出来。7应该是下一周的,但是一周七天,七天一换行,这是正常的。

7为什么出来,因为1前面是有一个空格。

所以i%& 只能是再没有空格的情况下,有空格怎么办

加上空格再取余。(i+dw)%7==0

再来推导,现在要输出6,dw=1 则,(1+6)%7==0 , 换行输出7。

输出13,dw=1 则,(1+13)%7==0 , 换行输出7。

输出20,dw=1 则,(1+20)%7==0 , 换行输出14。

输出27,dw=1 则,(1+27)%7==0 , 换行输出28。

这样,一个日历就出来了。

但是不够智能,我想怎么输入年和月,就可以判断这一个月的日历,

那我就接收年、月键盘录入、

然后定义方法,

先判断这一月有多少天,定义方法monthDays() 、但是每年的二月都是不固定的,所以判断闰年平年isLeapYear()然后就能知道天数的情况。

这个不难,问题是怎么月一号是星期几。

老师是这么讲的,先找一个基准年,我们就定1980年1月1日,这一天是星期二,那么定义变量int ww=2;

// 计数1号是星期几
public static int weekDay(int year, int month){
	int ww=2;  // 基准月,1980年1月1日是星期二
    int countDays=0;
    // 计算从1980年1月1日到year一共过了多少年,一共多少天
    for (int i = 1980; i < year; i++) {
    	countDays += 365 + isLeapYear(i);  // 一年365或者366
	}
	// 遍历1月1号到month一共过了多少个月,一共多少天
    for (int i = 1; i < month; i++) {
    	countDays += monthDays(year, i);
	}
    return (ww + countDays)%7;
}

然后就计算从1980年1月1日到现在(2002年8月1日)已经过去了多少天。

看着很难,很简单,分两步,两个循环。

 // 计算从1980年1月1日到year一共过了多少整年,一共多少天
for (int i = 1980; i < year; i++) {
	countDays += 365 + isLeapYear(i);  // 一年365或者366
}

注意这个循环范围,为什么不是i<=year ,如果是这样这个循环就是

1980 1981 1982 ... 2021 202

这样就默认2022年已经过完了。就要加上2022年的365天+365,我要查询2022年8月的日历,哪么2022年肯定是没有过完啊

所以

1980 1981 1982 ... 2021

计算出从1980~2022年一共过了多少个整年。

// 遍历1月1号到month一共过了多少个月,一共多少天
for (int i = 1; i < month; i++) {
	countDays += monthDays(year, i);
}

那就是计算从1月到8月一共过了多少个整月

然后说星期几dw怎么算。有这么个公式dw = (ww+countDays)%7 那就是直接套用公式。

因此万年历出来了。-

总结

大概写了该一万字了,大部分都是代码,还有我的思路,通过这种记录的学习方式我感觉更加让我理解这个题目的算法部分。如果不写记录,学完了就是学完了,然后学下一篇内容,也不是不可以。但是下一次遇到还是不会,这题我做过,让我再想想。

都不难,基础语法,没有用的算法,想起我之前用C语言再洛谷刷题,那是真的难。

老师说双色球难,我觉得吧难的是不懂双色球规则,就是对两个数组里的元素进行统计。

万年历是我们学校的一个案例,C语言和python都做了,想着Java也不例外,我以为我会做一周,也就是一个晚上,两小时左右。

好了,我的学习笔记到此结束。

里面肯定有许许多多的bug,欢迎大家指出!毕竟这样成长更快。

也感谢大家可以看到这样,如果帮到了你,是我的荣幸。

谢谢大家!

后就能知道天数的情况。

这个不难,问题是怎么月一号是星期几。

老师是这么讲的,先找一个基准年,我们就定1980年1月1日,这一天是星期二,那么定义变量int ww=2;

// 计数1号是星期几
public static int weekDay(int year, int month){
	int ww=2;  // 基准月,1980年1月1日是星期二
    int countDays=0;
    // 计算从1980年1月1日到year一共过了多少年,一共多少天
    for (int i = 1980; i < year; i++) {
    	countDays += 365 + isLeapYear(i);  // 一年365或者366
	}
	// 遍历1月1号到month一共过了多少个月,一共多少天
    for (int i = 1; i < month; i++) {
    	countDays += monthDays(year, i);
	}
    return (ww + countDays)%7;
}

然后就计算从1980年1月1日到现在(2002年8月1日)已经过去了多少天。

看着很难,很简单,分两步,两个循环。

 // 计算从1980年1月1日到year一共过了多少整年,一共多少天
for (int i = 1980; i < year; i++) {
	countDays += 365 + isLeapYear(i);  // 一年365或者366
}

注意这个循环范围,为什么不是i<=year ,如果是这样这个循环就是

1980 1981 1982 ... 2021 202

这样就默认2022年已经过完了。就要加上2022年的365天+365,我要查询2022年8月的日历,哪么2022年肯定是没有过完啊

所以

1980 1981 1982 ... 2021

计算出从1980~2022年一共过了多少个整年。

// 遍历1月1号到month一共过了多少个月,一共多少天
for (int i = 1; i < month; i++) {
	countDays += monthDays(year, i);
}

那就是计算从1月到8月一共过了多少个整月

然后说星期几dw怎么算。有这么个公式dw = (ww+countDays)%7 那就是直接套用公式。

因此万年历出来了。-

总结

大概写了该一万字了,大部分都是代码,还有我的思路,通过这种记录的学习方式我感觉更加让我理解这个题目的算法部分。如果不写记录,学完了就是学完了,然后学下一篇内容,也不是不可以。但是下一次遇到还是不会,这题我做过,让我再想想。

都不难,基础语法,没有用的算法,想起我之前用C语言再洛谷刷题,那是真的难。

老师说双色球难,我觉得吧难的是不懂双色球规则,就是对两个数组里的元素进行统计。

万年历是我们学校的一个案例,C语言和python都做了,想着Java也不例外,我以为我会做一周,也就是一个晚上,两小时左右。

好了,我的学习笔记到此结束。

里面肯定有许许多多的bug,欢迎大家指出!毕竟这样成长更快。

也感谢大家可以看到这样,如果帮到了你,是我的荣幸。

谢谢大家!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值