目录
一、前言
(1)第四次题目集
本次题目集一共有7道题目,题量适中,但第一题难度较大,其余题目难度适中。考察的知识点有类与类之间的关系调用、对象数组的使用、排序、String类方法的使用、JAVA封装性的理解与运用、各种时间日期类方法的使用。
(2)第五次题目集
本次题目集一共有6道题目集,体量适中,最后两题难度较大,其余题目比较简答,这次题目集主要考察的是正则表达式的运用,虽然不是很难,但是老师上课没有讲过,需要我们去自学,所以对自学的能力还是有一定要求的。最后两题还是老家伙,日期的设计,不过要改成聚合关系。
(3)第六次题目集
本次题目集人狠话不多,一道题,100分,6天,一个人。在这里我就不多赘言,下面我会详细的分析。
二、设计与分析
在此我拿出我认为比较有价值的题目拿出来分析,希望对这些题目能有更好的理解。
7-1 菜单计价程序-3
该题题目太长,我就大概简述一下我理解的题目大意,该题是想让我们做一个点菜系统,先是输入信息,包括菜单信息(菜名和价格)和订单信息(菜名、份额、份数、删除记录、代点菜、点菜时间)息,输出内容是每桌的价格,要注意的是,要判断该客户的点单时间在不在营业时间内,如果在的话,要判断该时间段内的折扣,带点菜订单的价格是算到帮点的那一桌,如果输入菜单信息的时候输入了一样的菜名,菜名价格以最后一条信息为主。 以上就是题目大意,下面展示一下该题目的类图。![](/i/l/?n=23&i=blog/3145726/202303/3145726-20230330155709978-1536665851.png)
通过上面类图可以看出有5个类,Main类,Dish类,Menu类,Order类,Record类。Menu类中包含着Dish类,Order类包含着Record类。Record类中new一个Record类的ArrayList的列表,方便对订单和菜单信息进行增删查改。我来说下我写这道题的一个思路,首先是处理输入信息,肯定是用循环输入信息,此处有2个标记点,“end”和“table”,“end”输入的标志的所有信息输入完毕,此时就要开始输出数据,“table”标志的是订单信息的输入与处理。输入处理完后开始处理数据,先初始化菜品的信息,再通过add方法将菜品的信息加入到菜单上,再初始化order,还要判断是否有删除和代点菜的信息处理,我是在类的属性中增加一些标志点来判断的,还要判断点菜的时间,计算折扣,最后将价格输出。 接下来我们来看一下SourceMonitor的分析
![](/i/l/?n=23&i=blog/3145726/202303/3145726-20230330163026464-1013142275.png)
最大复杂度太大了,我估计是判断的时候运用了大量的if else语句,还有这道题目本身逻辑的复杂些。
总的来说该题目的难度还是很大的,需要强大的逻辑能力,和对类关系深刻的理解与把握。
下面是源码参考
import java.util.*; import java.time.LocalDate; import java.time.DayOfWeek; public class Main { public static void main(String[] args){ Scanner sc = new Scanner(System.in); Menu menus = new Menu(); //读入菜品信息 String s = sc.nextLine(); while(!s.startsWith("table")&&!s.startsWith("end")){ String[] split = s.split(" "); menus.addDish(split[0], Integer.parseInt(split[1])); s = sc.nextLine(); } if(s.equals("end")){ return; } //读入订单消息 ArrayList<Order> orders = new ArrayList<>(); //每桌的订单 //String[] split = s.split(" "); orders.add(new Order(s)); s = sc.nextLine(); while(!s.equals("end")){ String[] split = s.split(" "); boolean flag = false; if(split.length == 2 && !split[1].equals("delete") ){ for(int i = 0; i < menus.dishes.size(); i++){ if(split[0].equals(menus.dishes.get(i).name)){ menus.dishes.get(i).unit_price = Integer.parseInt(split[1]); flag = true; break; } } if(flag == false){ menus.addDish(split[0], Integer.parseInt(split[1])); } }else if(s.startsWith("table")){//下一桌的标识 orders.add(new Order(s)); }else if(split[1].equals("delete")){//删除标识 int index = Integer.parseInt(split[0]); //要删除菜品的序号 if(index > 0 && index < orders.get(orders.size()-1).records.size()){ orders.get(orders.size()-1).delARecordByOrderNum(index); }else{ //删除错误 orders.get(orders.size()-1).error++; } }else if(split.length == 4){//点菜记录 int orderNum = Integer.parseInt(split[0]); String dishName = split[1]; int portion = Integer.parseInt(split[2]); int num = Integer.parseInt(split[3]); orders.get(orders.size()-1).addARecord(orderNum,dishName,portion,num); }else{//代点菜,加入当前订单 int tableNum =Integer.parseInt(split[0]); int orderNum = Integer.parseInt(split[1]); String dishName = split[2]; int portion = Integer.parseInt(split[3]); int num = Integer.parseInt(split[4]); orders.get(orders.size()-1).addARecord(orderNum,dishName,portion,num); orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size()-1).helpNum = tableNum; orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size()-1).isHelp = true; orders.get(orders.size()-1).isHelp = true; } s = sc.nextLine(); } //输出菜单Orders for(int i = 0; i < orders.size();i++){ System.out.println("table "+orders.get(i).tableNum+": "); for(int j = 0; j < orders.get(i).records.size(); j++){ if(menus.searthDish(orders.get(i).records.get(j).dishName) != null){ if(orders.get(i).records.get(j).isHelp == true){ System.out.println(orders.get(i).records.get(j).orderNum+" "+"table "+orders.get(i).tableNum+" pay for table "+orders.get(i).records.get(j).helpNum+" "+orders.get(i).records.get(j).getPrice(menus)); }else{ System.out.println(orders.get(i).records.get(j).orderNum+" "+orders.get(i).records.get(j).dishName+" "+orders.get(i).records.get(j).getPrice(menus)); } }else{ System.out.println(orders.get(i).records.get(j).dishName+" does not exist"); } } for(int k = 0; k < orders.get(i).error; k++){ System.out.println("delete error;"); } if(orders.get(i).isValidTime()){ orders.get(i).isWrong = true; }else{ orders.get(i).isWrong = false; } } for(int i = 0; i < orders.size();i++){ if(orders.get(i).isWrong){ System.out.println("table "+orders.get(i).tableNum+":"+" "+orders.get(i).getTotalPrice(menus)); }else{ System.out.println("table "+orders.get(i).tableNum+ " out of opening hours"); } } } } //菜品类 class Dish{ String name;//菜品名称 int unit_price; //单价 double price = 0.0; public Dish(){ } public Dish(String name,int unit_price){ this.name = name; this.unit_price = unit_price; } public int getPrice(int portion){ //计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) if(portion == 1){ price = unit_price * 1.0; }else if(portion == 2){ price = unit_price * 1.5; }else if(portion == 3){ price = unit_price * 2; } return (int)(Math.round(price)); } } //菜单类 class Menu{ ArrayList<Dish> dishes = new ArrayList<>(); //存放菜品信息 Dish searthDish(String dishName){//根据菜名在菜谱中查找菜品信息,返回Dish对象 for(int i = 0; i < dishes.size(); i++){ if(dishes.get(i).name.equals(dishName)){ return dishes.get(i); } } return null; //找不到该菜品 } Dish addDish(String dishName,int unit_price) {//添加一道菜品信息 Dish newDish = new Dish(dishName,unit_price); dishes.add(newDish); return newDish; } } //订单类 class Record { int orderNum;//序号 String dishName;//菜品 int portion;//份额(1/2/3代表小/中/大份) int num; //份数 boolean isHelp = false; boolean flag = true; int helpNum ; public Record(int orderNum,String dishName,int portion,int num){ this.orderNum = orderNum; this.dishName = dishName; this.portion = portion; this.num = num; } public int getPrice(Menu menus) {//计算本条记录的价格 Dish dish = menus.searthDish(this.dishName); if(dish == null){ return 0; } double price = 0; price = dish.getPrice(this.portion) * this.num; return (int)(Math.round(price)); } } class Order { int tableNum; int year ; int month ; int day; int hour; int min; int sec; int error = 0; boolean isWrong = false; boolean isHelp = false; ArrayList<Record> records = new ArrayList<>(); //存放订单每一单信息 public Order(String line) { String[] parts = line.split(" "); this.tableNum = Integer.parseInt(parts[1]); String[] dateParts = parts[2].split("/"); this.year = Integer.parseInt(dateParts[0]); this.month = Integer.parseInt(dateParts[1]); this.day = Integer.parseInt(dateParts[2]); String[] timeParts = parts[3].split("/"); this.hour = Integer.parseInt(timeParts[0]); this.min = Integer.parseInt(timeParts[1]); this.sec = Integer.parseInt(timeParts[2]); } public Record addARecord(int orderNum, String dishName, int portion, int num) {//添加一条菜品信息到订单中 Record record = new Record(orderNum, dishName, portion, num); records.add(record); return record; } public void delARecordByOrderNum(int orderNum) {//根据序号删除一条记录 for (int i = 0; i < records.size(); i++) { if (records.get(i).orderNum == orderNum) { records.get(i).flag = false; } } } public Record findRecordByNum(int orderNum) {//根据序号查找一条记录 for (int i = 0; i < records.size(); i++) { if (records.get(i).orderNum == orderNum) { return records.get(i); } } return null; //找不到 } public int getTotalPrice(Menu menus){//计算订单总价 double sum = 0.0; for(int i = 0; i < records.size(); i++){ if(records.get(i).flag){ sum += records.get(i).getPrice(menus); } } if(!isWeekend() && isLunch()){ sum = 0.6 * sum; }else if(!isWeekend() && isDinner()){ sum = 0.8 * sum; } return (int)(Math.round(sum)); } public boolean isWeekend(){ LocalDate date = LocalDate.of(this.year, this.month, this.day); DayOfWeek week = date.getDayOfWeek(); if(week == DayOfWeek.SATURDAY || week == DayOfWeek.SUNDAY) { return true; }else { return false; } } public boolean isLunch(){ double time = hour + (min/60.0); return (time >= 10.5) && (time <= 14.5); } public boolean isDinner(){ double time = hour + (min/60.0); return (time >= 17) && (time <= 20.5); } public boolean isValidTime(){ double time =hour + (min/60.0); return (isWeekend() &&(time >= 9.5 && time <= 21)) ||(!isWeekend() && (isDinner() || isLunch())); } }
7-3 去掉重复的数据
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。
你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,去掉所有重复的数字。最后按照输入顺序输出没有重复数字的数据。所有重复的数字只保留第一次出现的那份。
输入格式:
你的程序首先会读到一个正整数 n,1≤n≤100000。
然后是 n 个整数,这些整数的范围是 [1, 100000]。
输出格式:
在一行中按照输入顺序输出去除重复之后的数据。每两个数据之间有一个空格,行首尾不得有多余空格。
这道题的难度并不是很大,但是有很多的坑点,一开始看到这道题,我想到的是用双重暴力循环,但是最后一个测试点超时了,然后我想到先用sort()排序然后再循环,但是这样虽然不超时了,但与题目的输出格式不相符,最后我想到了用一个计数数组来标记去重,最后成功的通过所以的测试点。
下面是源码
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] a = new int[1000001]; int num = 0; num = sc.nextInt(); System.out.print(num); a[num]++; for(int i = 0; i < n-1; i++){ num = sc.nextInt(); if(a[num] == 0){ System.out.print(" "+num); a[num]++; } } } }
7-5 日期问题面向对象设计(聚合一)
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下:
Wrong Format
- 当第一个数字为1且输入均有效,输出格式如下:
year-month-day
- 当第一个数字为2且输入均有效,输出格式如下:
year-month-day
- 当第一个数字为3且输入均有效,输出格式如下:
天数值
这道题前面已经写了很多版本了,基本的算法和逻辑已经基本掌握清楚了,这道题题目要求改成聚合关系,所以只要将类作为其他类的属性就行了,整体的逻辑没变,只是调用方法的方式不一样,下面是我的类图和题目要求差不多,这道题目要注意的地方还是边界月份年份还有日的变化。
接下看下sourceMoniter的分析结果
可以看出复杂度还是有点高,代码还有可以继续优化的地方。
7-6 日期问题面向对象设计(聚合二) 分数 34 作者 段喜龙 单位 南昌航空大学参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下:
Wrong Format
- 当第一个数字为1且输入均有效,输出格式如下:
year1-month1-day1 next n days is:year2-month2-day2
- 当第一个数字为2且输入均有效,输出格式如下:
year1-month1-day1 previous n days is:year2-month2-day2
- 当第一个数字为3且输入均有效,输出格式如下:
The days between year1-month1-day1 and year2-month2-day2 are:值
和题目要求的相似,有了之前的基础这道题就没什么好说的了,看一下分析结果吧
感觉和上题的情况差不多,还有很大的进步空间,写出更有质量的代码和逻辑清晰的结构。
接下来看下源码
package 日期1; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = 0; int year = 0; int month = 0; int day = 0; int choice = input.nextInt(); if(choice == 1){ year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); DateUtil date = new DateUtil(year,month,day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print(year + "-" + month+ "-" + day + " next " + n + " days is:"); System.out.println(date.getNextNDays(n).showDate()); }else if (choice == 2) { year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); DateUtil date = new DateUtil(year, month, day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print( year + "-" + month + "-" + day+ " previous " + n + " days is:"); System.out.println(date.getPreviousNDays(n).showDate()); } else if (choice == 3) { year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); int anotherYear = Integer.parseInt(input.next()); int anotherMonth = Integer.parseInt(input.next()); int anotherDay = Integer.parseInt(input.next()); DateUtil fromDate = new DateUtil(year, month, day); DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { System.out.println("The days between " + fromDate.showDate() + " and " + toDate.showDate() + " are:" + fromDate.getDaysofDates(toDate)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } } class Year{ private int value; public Year(){ } public Year(int value){ this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } boolean isLeapYear(){ if((this.value%4 == 0 && this.value%100 != 0) || (this.value % 400 == 0)){ return true; }else{ return false; } } public boolean validate(){ if(this.value >= 1820 && this.value <= 2020){ return true; }else{ return false; } } public void yearIncrement(){ this.value++; } public void yearReduction(){ this.value--; } } class Month{ private int value; public Month() { } public Month( int value){ this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public void resetMin(){ this.value = 1; } public void resetMax(){ this.value = 12; } public boolean validate(){ if(this.value >= 1 && this.value <= 12){ return true; }else{ return false; } } public void monthIncrement(){ this.value++; } public void monthReduction(){ this.value--; } } class Day{ private int value; public Day(){ } public Day(int value){ this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public void dayIncrement(){ this.value++; } public void dayReduction(){ this.value--; } } class DateUtil{ private Year year; private Month month; private Day day; int[] mon_maxnum ={31,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(){ } public DateUtil(int y, int m, int d){ year = new Year(y); month = new Month(m); day = new Day(d); } public Year getYear() { return year; } public void setYear(Year year) { this.year = year; } public Month getMonth() { return month; } public void setMonth(Month month) { this.month = month; } public Day getDay() { return day; } public void setDay(Day day) { this.day = day; } public void setDayMin(){ day.setValue(1); } public void setDayMax(){ if(this.year.isLeapYear()){ mon_maxnum[2]=29; } this.day.setValue(mon_maxnum[this.month.getValue()]); } public boolean checkInputValidity(){ if(day.getValue() >= 1 && day.getValue() <= mon_maxnum[this.month.getValue()] && this.month.validate() && this.year.validate()){ return true; }else{ return false; } } public boolean compareDates(DateUtil date){ if(this.year.getValue() > date.year.getValue()){ return true; }else if(this.year.getValue() == date.year.getValue() && this.month.getValue() > date.month.getValue()){ return true; }else if(this.year.getValue() == date.year.getValue() && this.month.getValue() == date.month.getValue() && this.day.getValue() > date.day.getValue()){ return true; } return false; } public boolean equalTwoDates(DateUtil date){ if((this.year.getValue() == date.year.getValue()) && (this.month.getValue() == date.month.getValue()) && (this.day.getValue() == date.getDay().getValue())){ return true; } return false; } public String showDate(){ return this.year.getValue() + "-" + this.month.getValue() + "-" + this.day.getValue(); } public DateUtil getNextNDays(int n){ DateUtil d; d = this; while(n > 0){ d.getDay().dayIncrement(); n--; if( d.year.isLeapYear()){ mon_maxnum[2] = 29; if( d.day.getValue() > mon_maxnum[d.month.getValue()]){ d.month.monthIncrement(); setDayMin(); if( d.month.getValue() == 13){ d.month.resetMin(); d.year.yearIncrement(); } } }else{ mon_maxnum[2] = 28; if( d.day.getValue() > mon_maxnum[d.month.getValue()]){ d.month.monthIncrement(); setDayMin(); if( d.month.getValue() == 13){ d.month.resetMin(); d.year.yearIncrement(); } } } } return d; } public DateUtil getPreviousNDays(int n){ DateUtil d; d = this; while(n > 0){ d.getDay().dayReduction(); n--; if( d.year.isLeapYear()){ mon_maxnum[2] = 29; if( d.day.getValue() < 1 ){ d.month.monthReduction(); setDayMax(); if( d.month.getValue() == 0){ d.month.resetMax(); d.year.yearReduction(); } } }else{ mon_maxnum[2] = 28; if( d.day.getValue() < 1 ){ d.month.monthReduction(); setDayMax(); if( d.month.getValue() == 0){ d.month.resetMax(); d.year.yearReduction(); } } } } return d; } public int getDaysofDates(DateUtil date){ if(equalTwoDates(date)){ return 0; }else{ DateUtil k = this; if(!compareDates(date)){ DateUtil t = date; date = k; k = t; } int sum1 = 0; int sum2 = 0; int sum3 = 0; if (k.year.isLeapYear()) { mon_maxnum[2] = 29; } for (int i = 0; i < k.month.getValue() - 1; i++) { sum1 += mon_maxnum[i+1] ; } sum1 += k.day.getValue(); if (!date.year.isLeapYear()){ mon_maxnum[2] = 28; } for (int i = 0; i < date.month.getValue() - 1; i++) { sum2 += mon_maxnum[i+1]; } sum2 += date.day.getValue(); while(k.year.getValue() != date.year.getValue()){ if(date.year.isLeapYear()){ sum3+= 366; }else{ sum3 += 365; } date.year.yearIncrement(); } int sum = sum1 - sum2 + sum3; return sum; } } }
7-1 菜单计价程序-4
和前面的菜单系统差不多,不过添加了特色菜还有一堆的条件限制
1、菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish"
2、桌号所带时间格式合法(格式见输入格式部分说明,其中年必须是4位数字,月、日、时、分、秒可以是1位或2位数),数据非法,比如:2023/15/16 ,输出桌号+" date error"
3、同一桌菜名、份额相同的点菜记录要合并成一条进行计算,否则可能会出现四舍五入的误差。
4、重复删除,重复的删除记录输出"deduplication :"+序号。
5、代点菜时,桌号不存在,输出"Table number :"+被点菜桌号+" does not exist";本次作业不考虑两桌记录时间不匹配的情况。
6、菜谱信息中出现重复的菜品名,以最后一条记录为准。
7、如果有重复的桌号信息,如果两条信息的时间不在同一时间段,(时段的认定:周一到周五的中午或晚上是同一时段,或者周末时间间隔1小时(不含一小时整,精确到秒)以内算统一时段),此时输出结果按不同的记录分别计价。
8、重复的桌号信息如果两条信息的时间在同一时间段,此时输出结果时合并点菜记录统一计价。前提:两个的桌号信息的时间都在有效时间段以内。计算每一桌总价要先合并符合本条件的饭桌的点菜记录,统一计价输出。
9、份额超出范围(1、2、3)输出:序号+" portion out of range "+份额,份额不能超过1位,否则为非法格式,参照第13条输出。
10、份数超出范围,每桌不超过15份,超出范围输出:序号+" num out of range "+份数。份数必须为数值,最高位不能为0,否则按非法格式参照第16条输出。
11、桌号超出范围[1,55]。输出:桌号 +" table num out of range",桌号必须为1位或多位数值,最高位不能为0,否则按非法格式参照第16条输出。
12、菜谱信息中菜价超出范围(区间(0,300)),输出:菜品名+" price out of range "+价格,菜价必须为数值,最高位不能为0,否则按非法格式参照第16条输出。
13、时间输入有效但超出范围[2022.1.1-2023.12.31],输出:"not a valid time period"
14、一条点菜记录中若格式正确,但数据出现问题,如:菜名不存在、份额超出范围、份数超出范围,按记录中从左到右的次序优先级由高到低,输出时只提示优先级最高的那个错误。
15、每桌的点菜记录的序号必须按从小到大的顺序排列(可以不连续,也可以不从1开始),未按序排列序号的输出:"record serial number sequence error"。当前记录忽略。(代点菜信息的序号除外)
16、所有记录其它非法格式输入,统一输出"wrong format"
17、如果记录以“table”开头,对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理。如果记录不是以“table”开头,比如“tab le 55 2023/3/2 12/00/00”,该条记录认为是错误记录,后面所有的信息并入上一桌一起计算。
已经开始害怕了,博主能力有限只能讲下大概的逻辑。这道题目最重要的是要处理输入的信息,一开始我是用contains()和equals()和startWith()这几个函数还有长度来判断信息属于哪一类,后面发现太麻烦了而且一些格式错误的信息有时候判断不了,后面想到了之前题目集老师布置的正则表达式的训练,想起来用正则表达式可以处理复杂的文字消息和格式规定,所以后面我就改成了正则表示来判断消息的输入,代码量简化了不少,我觉的我拿不到满分的问题是对这个输出的格式不是很清楚,我代码的逻辑还是比较清晰的,当然也可能是博主的理解力不够,毕竟也有满分的选手,还有判断日期的时候没有用日期类的方法,增加了不少的代码量,这个地方是可以优化的,接下来看下我的类图
可以看出类图并不复杂,类和类之间的关系也很简单,所以可以看出博主还有很大的提升空间,需要更加的刻苦学习,当然这道题目没有满分的还有一个原因就是意志力,因为我当时写了2天后,一提交34分,后面测试代码测了一两天,分数来到了65,后面实在是测得烦,就直接摆了,看来还是需要锻炼一下抗压能力,感觉在段王爷的施压下,我会成长很多。最后来看下源代码吧
import java.time.DayOfWeek; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.Scanner; public class Main { public static void main(String[] args) { //处理信息输入 Scanner input = new Scanner(System.in); String s = input.nextLine(); String regex = "[\\u4e00-\\u9fa5]+ [1-9]{1}[0-9]*"; //菜单 String regexT = "[\\u4e00-\\u9fa5]+ [1-9]{1}[0-9]* T"; //特色 String regex1 = "table [1-9]{1}[0-9]* [1-9][0-9]{3}/[0-9]{1,2}/[0-9]{1,2} [0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2}"; //桌号 String regex2 = "[0-9]+ [\\u4e00-\\u9fa5]+ [0-9]+ [0-9]+";//订单 String regex3 = "[0-9]+ delete";//删除 String regex4 = "[0-9]+ [0-9]+ [\\u4e00-\\u9fa5]+ [0-9]+ [0-9]+";//代点 Menu menu = new Menu(); ArrayList<Order> orders = new ArrayList<>(); boolean flag1 = false; boolean flag = false; boolean isOrder = false; while(true){ String[] split = s.split(" "); if(s.contains("/")) { isOrder = true; } if(s.equals("end")){ //结束信息输入 break; }else if((s.matches(regexT) || s.matches(regex))){ //菜品信息 if(!isOrder){ //菜谱信息中出现重复的菜品名,以最后一条记录为准。 for(int i = 0; i < menu.dishes.size(); i++){ if(split[0].equals(menu.dishes.get(i).name)){ menu.dishes.get(i).unit_price = Integer.parseInt(split[1]); if(s.contains("T")){ menu.dishes.get(i).isT = true; } break; } } //没遇到重复的,菜品加入菜单 //菜谱信息中菜价超出范围(区间(0,300)),输出:菜品名+" price out of range "+价格, // 菜价必须为数值,最高位不能为0,否则按非法格式参照第16条输出。 if(Integer.parseInt(split[1]) > 0 && Integer.parseInt(split[1]) < 300){ menu.addDish(split[0], Integer.parseInt(split[1])); if(s.contains("T")){ menu.dishes.get(menu.dishes.size() - 1).isT = true; } }else{ System.out.println(split[0]+" price out of range "+Integer.parseInt(split[1])); } }else{ System.out.println("invalid dish"); } }else if(s.startsWith("table")){ //订单消息开始的标志 if(s.matches(regex1)){ orders.add(new Order(s)); } //桌号格式错误(以“table”开头)+订单格式错误(忽略) if(!s.matches(regex1)){ System.out.println("wrong format"); s = input.nextLine(); while(!s.contains("/") && !s.equals("end") ){ //订单过滤 flag = true; s = input.nextLine(); } }else { //格式正确 //System.out.println("table "+split[1]+": "); boolean a = false; //标记数据是不是非法 //桌号所带时间格式合法(格式见输入格式部分说明,其中年必须是4位数字,月、日、时、分、秒可以是1位或2位数), // 数据非法,比如:2023/15/16 ,输出桌号+" date error" //时间输入有效但超出范围[2022.1.1-2023.12.31],输出:"not a valid time period" //桌号超出范围[1,55]。输出:桌号 +" table num out of range", // 桌号必须为1位或多位数值,最高位不能为0,否则按非法格式参照第16条输出。 //如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours" if(Integer.parseInt(split[1]) > 55 && Integer.parseInt(split[1]) < 1){ orders.remove(orders.size() - 1); System.out.println(" table num out of range"); a = true; } if(orders.get(orders.size() - 1).monthValidate() && orders.get(orders.size() - 1).dayValidate() && orders.get(orders.size() - 1).isRT()){ if(orders.get(orders.size() - 1).year >= 2024){ System.out.println("not a valid time period"); orders.remove(orders.size() - 1); a = true; } }else{ if(orders.get(orders.size() - 1).year >= 2024){ System.out.println("not a valid time period"); orders.remove(orders.size() - 1); a = true; } System.out.println(Integer.parseInt(split[1])+" date error"); orders.remove(orders.size() - 1); a = true; } // if(orders.get(orders.size() - 1).isValidTime()) //重复桌号信息 if(findOrderByNum(Integer.parseInt(split[1]),orders) != null){ if(isSameTime(orders.get(orders.size() - 1),orders.get(orders.size() - 2))){ orders.remove(orders.size() - 1); } } if(a){ s = input.nextLine(); while(!s.contains("/") && !s.equals("end") ){ //订单过滤 flag = true; s = input.nextLine(); } } } }else if(s.matches(regex3)){ //删除订单 //重复删除,重复的删除记录输出"deduplication :"+序号。 int index = Integer.parseInt(split[0]); //要删除菜品的序号 if(orders.size() > 0){ if(orders.get(orders.size()-1).findRecordByNum(index) != null){ orders.get(orders.size()-1).delARecordByOrderNum(index); }else{ //删除错误 System.out.println("delete error;"); } } }else if(s.matches(regex4)){ boolean isExit = false; //代点餐 //桌号不存在,输出"Table number :"+被点菜桌号+" does not exist"; int tableNum =Integer.parseInt(split[0]); for(int i = 0; i < orders.size(); i++){ if(tableNum == orders.get(i).tableNum){ isExit = true; break; } } if(isExit){ int orderNum = Integer.parseInt(split[1]); String dishName = split[2]; if(menu.searthDish(dishName) == null){ System.out.println(dishName+" "+"does not exist"); }else{ int portion = Integer.parseInt(split[3]); int num = Integer.parseInt(split[4]); orders.get(orders.size()-1).addARecord(orderNum,dishName,portion,num); orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size()-1).helpNum = tableNum; orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size()-1).isHelp = true; orders.get(orders.size()-1).isHelp = true; System.out.println(orders.get(orders.size() - 1).records.get(orders.get(orders.size() - 1).records.size() - 1).orderNum+" "+"table"+" "+orders.get(orders.size() - 1).tableNum+" pay for table "+tableNum+" "+orders.get(orders.size() - 1).records.get(orders.get(orders.size() - 1).records.size() - 1).getPrice(menu)); } }else{ System.out.println("Table number :"+tableNum+" does not exist"); } }else if(s.matches(regex2)){ //订餐信息 //一条点菜记录中若格式正确,但数据出现问题 // ,如:菜名不存在、份额超出范围、份数超出范围,按记录中从左到右的次序优先级由高到低,输出时只提示优先级最高的那个错误。 //份额超出范围(普通菜不是1、2、3,特色菜不是1、3)输出:序号+" portion out of range "+份额, // 份额不能超过1位,否则为非法格式,参照第13条输出。 //份数超出范围,每桌不超过15份,超出范围输出: // 序号+" num out of range "+份数。份数必须为数值,最高位不能为0,否则按非法格式参照第16条输出。 //每桌的点菜记录的序号必须按从小到大的顺序排列(可以不连续,也可以不从1开始), // 未按序排列序号的输出:"record serial number sequence error"。当前记录忽略。(代点菜信息的序号除外 if(flag) { System.out.println("table "+split[1]+": "); flag = false; } if(menu.searthDish(split[1]) == null){ System.out.println(split[1]+" "+"does not exist"); }else if(menu.searthDish(split[1]).isT){ if(Integer.parseInt(split[2]) != 1 && Integer.parseInt(split[2]) != 2 && Integer.parseInt(split[2]) != 3){ System.out.println(split[0]+" portion out of range "+split[2]); }else if(Integer.parseInt(split[3]) >= 15) { System.out.println(split[0] + " num out of range " + split[3]); }else{ int num = 0; //最后一个不是代买的编号 if(orders.size() > 0){ if(orders.get(orders.size()-1).records.size() != 0){ for(int i = 0; i < orders.get(orders.size()-1).records.size(); i++){ if(!orders.get(orders.size()-1).records.get(i).isHelp){ num = orders.get(orders.size()-1).records.get(i).orderNum; } } if(Integer.parseInt(split[0]) > num){ orders.get(orders.size()-1).addARecord(Integer.parseInt(split[0]),split[1],Integer.parseInt(split[2]),Integer.parseInt(split[3])); System.out.println(split[0]+" "+split[1]+" "+ orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size() - 1).getPrice(menu)); }else{ System.out.println("record serial number sequence error"); } }else if(orders.get(orders.size()-1).records.size() == 0){ orders.get(orders.size()-1).addARecord(Integer.parseInt(split[0]),split[1],Integer.parseInt(split[2]),Integer.parseInt(split[3])); System.out.println(split[0]+" "+split[1]+" "+ orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size() - 1).getPrice(menu)); } } } }else if(!menu.searthDish(split[1]).isT){ if(Integer.parseInt(split[2]) != 1 && Integer.parseInt(split[2]) != 2 && Integer.parseInt(split[2]) != 3){ System.out.println(split[0]+" portion out of range "+split[2]); }else if(Integer.parseInt(split[3]) >= 15) { System.out.println(split[0] + " num out of range " + split[3]); }else{ int num = 0; //最后一个不是代买的编号 if(orders.get(orders.size()-1).records.size() != 0){ for(int i = 0; i < orders.get(orders.size()-1).records.size(); i++){ if(!orders.get(orders.size()-1).records.get(i).isHelp){ num = orders.get(orders.size()-1).records.get(i).orderNum; } } if(Integer.parseInt(split[0]) > num){ //合并份额相同的 if(orders.get(orders.size()-1).findRecordByName(split[1],Integer.parseInt(split[2])) != null){ orders.get(orders.size()-1).findRecordByName(split[1],Integer.parseInt(split[2])).num += Integer.parseInt(split[3]); split[3] = "0"; } orders.get(orders.size()-1).addARecord(Integer.parseInt(split[0]),split[1],Integer.parseInt(split[2]),Integer.parseInt(split[3])); System.out.println(split[0]+" "+split[1]+" "+ orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size() - 1).getPrice(menu)); }else{ System.out.println("record serial number sequence error"); } }else if(orders.get(orders.size()-1).records.size() == 0){ orders.get(orders.size()-1).addARecord(Integer.parseInt(split[0]),split[1],Integer.parseInt(split[2]),Integer.parseInt(split[3])); System.out.println(split[0]+" "+split[1]+" "+ orders.get(orders.size()-1).records.get(orders.get(orders.size()-1).records.size() - 1).getPrice(menu)); } } } }else{ System.out.println("wrong format"); } if(!flag){ s = input.nextLine(); } } for(int i = 0; i < orders.size() - 1; i++){ for(int j = 0; j < orders.size() - 1 - i; j++){ if(orders.get(j).tableNum > orders.get(j+1).tableNum){ Collections.swap(orders, j, j+1); } } } for(int i = 0; i < orders.size(); i++){ orders.get(i).getTotalPrice(menu); } } public static Order findOrderByNum(int tableNum,ArrayList<Order> orders){ if(orders.size() == 1){ return null; } for(int i = 0; i < orders.size() - 1; i++){ if(orders.get(i).tableNum == tableNum){ return orders.get(i); } } return null; } public static boolean isSameTime(Order order1,Order order2){ if(order1.year == order2.year && order1.month == order2.month && order1.day == order2.day){ if(order1.isWeekend()){ if(Math.abs((order1.hour * 3600 + order1.min * 60 +order1.sec) - (order2.hour * 3600 + order2.min * 60 +order2.sec)) >= 3600){ return false; }else{ return true; } }else{ if((order1.isLunch() && order2.isLunch()) || (order1.isDinner() && order1.isDinner())){ return true; }else{ return false; } } }else{ return false; } } } //每道菜品信息 class Dish { String name;//菜品名称 int unit_price; //单价 boolean isT = false; public Dish(){ } public Dish(String name,int unit_price){ this.name = name; this.unit_price = unit_price; } public int getPrice(int portion){ //计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) double price = 0.0; if(portion == 1){ price = unit_price * 1.0; }else if(portion == 2){ price = unit_price * 1.5; }else if(portion == 3){ price = unit_price * 2; } return (int)(Math.round(price)); } } //菜单--储存菜品 class Menu { ArrayList<Dish> dishes = new ArrayList<>(); //存放菜品信息 public Dish searthDish(String dishName){//根据菜名在菜谱中查找菜品信息,返回Dish对象 for(int i = 0; i < dishes.size(); i++){ if(dishes.get(i).name.equals(dishName)){ return dishes.get(i); } } return null; //找不到该菜品 } public Dish addDish(String dishName,int unit_price) {//添加一道菜品信息 Dish newDish = new Dish(dishName,unit_price); dishes.add(newDish); return newDish; } } class Record { int orderNum;//序号 String dishName;//菜品 int portion;//份额(1/2/3代表小/中/大份) int num; //份数 boolean isHelp = false; int deleteNum = 0; //删除次数 int helpNum ; public Record(int orderNum,String dishName,int portion,int num){ this.orderNum = orderNum; this.dishName = dishName; this.portion = portion; this.num = num; } public int getPrice(Menu menus) {//计算本条记录的价格 Dish dish = menus.searthDish(this.dishName); if(dish == null){ return 0; } double price = 0; price = dish.getPrice(this.portion) * this.num; return (int)(Math.round(price)); } } class Order { int tableNum; int year ; int month; int day ; int hour = 25; int min = 61; int sec = 61; int[] mon_maxnum ={31,31,28,31,30,31,30,31,31,30,31,30,31,31}; // int error = 0; boolean isHelp = false; //boolean isWrong = false; ArrayList<Record> records = new ArrayList<>(); //存放订单每一单信息 public Order(String line) { String[] parts = line.split(" "); this.tableNum = Integer.parseInt(parts[1]); //String regex = "([1-9][0-9]{3})/([0-9][0-9]|[0-9])/([0-9][0-9]|[0-9])"; String[] dateParts = parts[2].split("/"); this.year = Integer.parseInt(dateParts[0]); this.month = Integer.parseInt(dateParts[1]); this.day = Integer.parseInt(dateParts[2]); // String regex1 = "[0-9]{2}/[0-9]{2}/[0-9]{2}"; String[] timeParts = parts[3].split("/"); this.hour = Integer.parseInt(timeParts[0]); this.min = Integer.parseInt(timeParts[1]); this.sec = Integer.parseInt(timeParts[2]); } public Record addARecord(int orderNum, String dishName, int portion, int num) {//添加一条菜品信息到订单中 Record record = new Record(orderNum, dishName, portion, num); records.add(record); return record; } public void delARecordByOrderNum(int orderNum) {//根据序号删除一条记录 for (int i = 0; i < records.size(); i++) { //重复删除,重复的删除记录输出"deduplication :"+序号。 if (records.get(i).orderNum == orderNum) { records.get(i).deleteNum++; if(records.get(i).deleteNum > 1){ System.out.println("deduplication "+orderNum); } } } } public Record findRecordByNum(int orderNum) {//根据序号查找一条记录 for (int i = 0; i < records.size(); i++) { if (records.get(i).orderNum == orderNum) { return records.get(i); } } return null; //找不到 } public Record findRecordByName(String name, int portion) {//根据序号查找一条记录 for (int i = 0; i < records.size(); i++) { if (records.get(i).dishName == name && records.get(i).portion == portion) { return records.get(i); } } return null; //找不到 } public void getTotalPrice(Menu menus){//计算订单总价 double sum = 0.0; double price = 0.0; double cost = 0.0; for(int i = 0; i < records.size(); i++){ if(0 == records.get(i).deleteNum){ if(!isWeekend() && isLunch()){ if(menus.searthDish(records.get(i).dishName).isT){ price = records.get(i).getPrice(menus) * 0.7; }else{ price = 0.6 * records.get(i).getPrice(menus); } }else if(isWeekend() && isLunch()){ price = records.get(i).getPrice(menus); }else if(isWeekend() && isLunch()){ price = records.get(i).getPrice(menus); }else if(!isWeekend() && isDinner()){ if(menus.searthDish(records.get(i).dishName).isT){ price = records.get(i).getPrice(menus) * 0.7; }else{ price = 0.8 * records.get(i).getPrice(menus); } } cost += records.get(i).getPrice(menus); sum += price; } } if(isValidTime()){ System.out.println("table"+" "+tableNum+": "+(int)(Math.round(cost))+" "+(int)(Math.round(sum))); }else{ System.out.println("table"+" "+tableNum+" out of opening hours"); } } public boolean isWeekend(){ LocalDate date = LocalDate.of(this.year, this.month, this.day); DayOfWeek week = date.getDayOfWeek(); if(week == DayOfWeek.SATURDAY || week == DayOfWeek.SUNDAY) { return true; }else { return false; } } public boolean isLunch(){ double time = hour + (min/60.0); return (time >= 10.5) && (time <= 14.5); } public boolean isDinner(){ double time = hour + (min/60.0); return (time >= 17) && (time <= 20.5); } public boolean isValidTime(){ double time =hour + (min/60.0); return ( (isWeekend() &&(time >= 9.5 && time <= 21.5)) ||(!isWeekend() && (isDinner() || isLunch())) ); } public boolean dayValidate(){ if(isLeapYear(this.year)){ mon_maxnum[2] = 29; } if(this.day >= 1 && this.day <= mon_maxnum[this.month]){ return true; }else{ return false; } } public boolean isRT(){ if(this.hour < 24 && this.min < 60 && this.sec < 60) { return true; }else{ return false; } } public boolean monthValidate(){ if(this.month >= 1 && this.month <= 12){ return true; }else{ return false; } } public boolean isLeapYear(int year){ if((year%4 == 0 && year%100 != 0) || (year% 400 == 0)){ return true; }else{ return false; } } }
三、踩坑心得
1.在使用正则表达式的时候空格要注意打,因为这是要匹配的,由于博主书写代码的习惯很喜欢打空格,所以在此提醒下大家
2.在使用IntergeparseInt()这个函数的情况下,一定要保证格式的正确,不然会发生转化异常
3.以后在格式判断的题目中,一定要用正则表达式,太好用了
四、改进建议
1.在遇到难题时,不要放弃,应该经常深入思考和讨论,并尝试寻找更多的资料和范例来帮助理解。多看老师课上讲授的相关知识点,加强对基本操作的掌握,逐步积累编程思维能力。
2.在代码设计过程中还需要注意模块化思想,即将大问题拆分为小问题进行解决,并考虑代码重复利用率和可维护性等因素。
3.与其跟着检查点走,不如在开始进行设计前,先考虑程序可能会遇见的特殊情况,在自我调试中对代码进行修改,这样不仅仅可以让设计思路更加简单易懂,同时在优化代码时也更加便捷,不那么容易写出**代码
五、总结
在本阶段的三次题目集中,我学习了很多有关Java编程语言的知识,从基础的数据类型、控制结构、数组到面向对象编程,包括对类进行了初步的学习。在学习过程中,我发现我需要进一步学习和研究的地方,例如如何优化代码性能、如何处理异常和错误等问题。关于教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见,我认为教师可以在授课时注重理论和实践相结合,增加实际应用案例的讲解,这样可以更好地帮助学生理解Java编程语言的特点和应用场景。在课上和课下组织方式上,可以采用更多的小组合作、讨论和分享方式,让学生更好地相互学习和交流经验。还有Pta的题目多给点测试点,最后希望老师狠狠的给我压力,多骂骂我。还有老师能不能把题目的源代码和课上设计模式的源代码发出来出来参考参考啊,错题一直错,没有进步。
标签:总结,题目,get,int,OOP,parseInt,size,orders,split From: https://www.cnblogs.com/lbsblog/p/17364378.html