练习一:飞机票
需求
- 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
- 按照如下规则计算机票价格:旺季(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+1
,number=1
;a[0] = 1
第2次循环,number = 1*10+2 = 10+2
,number=12
;a[0] = 2`
第3次循环,number = 12*10+3 = 120+3
,number=123
;a[0] = 3
第4次循环,number = 123*10+4 = 1230 + 4
,number=1234
;a[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=6
、16%10=6
、26%10=6
、36%10=6
、46%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=6
、16%10=6
、26%10=6
、36%10=6
、46%10=6
、…
16、26、36…是已经超出范围的,之间pass。
密码 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
+5 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 12 | 14 |
%10 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 |
然后就可以通过表格发现如果取余后的数字(需要解密的数字)在5~9这个范围,那么取余前的数字与取余后的数字相等、一致。
如果在10~14之间,那么取余前 = 取余后+10
因此就解决了,加密有个+5的过程,那么取余就是-5
假设密码是3
,那么3+5=8
,8%10=8
,加密是8
;对8
解密,因为(8>5 && 8<9)
,8=8
, 8-5=3
, 解密是3
假设密码是7
,那么7+5=12
,12%10=2
,加密是2
;对2
解密,因为(2>0 && 2<4)
,2+10=12
, 12-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索引进行交换就可以了。可以说这个五次循环就可以了。
上的解法一起码有五五二十五次循环。
练习九:双色球
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
有没有…;再看最后一位蓝球是不是相同,
最后发现红球中11
,25
, 15
这三个号码与本期号码相同,蓝球也是9
和9
一样
得出结果,红球中了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,欢迎大家指出!毕竟这样成长更快。
也感谢大家可以看到这样,如果帮到了你,是我的荣幸。
谢谢大家!