java第二次Blog作业
1、前言:
这三次pta难度比上次明显增加,已经有部分题目写不完了,知识点涉及也比较广,题量提升不大但难度增加了,这次pta也是做的最差的一次。
题目集04除了第一题比较难其他都不太难,第四题稍微有一点难度,题目集05除了最后两题都比较简单,最后两题是前面类似的题目,但加了其他的条件,多花了一点时间。题目集06难度就大了很多,跟以前相比内容太多了,逻辑也有点复杂。
2、试题分析:
题目集4
7-1 菜单计价程序-3

设计点菜计价程序,根据输入的信息,计算并输出总价格。 输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。 菜单由一条或多条菜品记录组成,每条记录一行 每条菜品记录包含:菜名、基础价格 两个信息。 订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。 桌号标识独占一行,包含两个信息:桌号、时间。 桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。 点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。 不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。 删除记录格式:序号 delete 标识删除对应序号的那条点菜记录。 如果序号不对,输出"delete error" 代点菜信息包含:桌号 序号 菜品名称 份额 分数 代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。 程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。 每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。 折扣的计算方法(注:以下时间段均按闭区间计算): 周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。 周末全价,营业时间:9:30-21:30 如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours" 参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。 Dish { String name;//菜品名称 int unit_price; //单价 int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) } 菜谱类:对应菜谱,包含饭店提供的所有菜的信息。 Menu { Dish\[\] dishs ;//菜品数组,保存所有菜品信息 Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。 Dish addDish(String dishName,int unit_price)//添加一道菜品信息 } 点菜记录类:保存订单上的一道菜品记录 Record { int orderNum;//序号\\ Dish d;//菜品\\ int portion;//份额(1/2/3代表小/中/大份)\\ int getPrice()//计价,计算本条记录的价格\\ } 订单类:保存用户点的所有菜的信息。 Order { Record\[\] records;//保存订单上每一道的记录 int getTotalPrice()//计算订单的总价 Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。 delARecordByOrderNum(int orderNum)//根据序号删除一条记录 findRecordByNum(int orderNum)//根据序号查找一条记录 } ### 输入格式: 桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS) 菜品记录格式: 菜名+英文空格+基础价格 如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。 点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。 删除记录格式:序号 +英文空格+delete 代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数 最后一条记录以“end”结束。 ### 输出格式: 按输入顺序输出每一桌的订单记录处理信息,包括: 1、桌号,格式:table+英文空格+桌号+”:” 2、按顺序输出当前这一桌每条订单记录的处理信息, 每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名 如果删除记录的序号不存在,则输出“delete error” 最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价 本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。 输入格式: 桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS) 菜品记录格式: 菜名+英文空格+基础价格 如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。 点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。 删除记录格式:序号 +英文空格+delete 代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数 最后一条记录以“end”结束。 输出格式: 按输入顺序输出每一桌的订单记录处理信息,包括: 1、桌号,格式:table+英文空格+桌号+“:” 2、按顺序输出当前这一桌每条订单记录的处理信息, 每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名 如果删除记录的序号不存在,则输出“delete error” 最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价 本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

麻婆豆腐 12 油淋生菜 9 table 1 2023/3/22 12/2/3 1 麻婆豆腐 2 2 2 油淋生菜 1 3 end

table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1: 38

麻婆豆腐 12 油淋生菜 9 table 1 2023/3/22 17/0/0 1 麻婆豆腐 2 2 2 油淋生菜 1 3 1 delete end

table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1: 22

麻婆豆腐 12 油淋生菜 9 table 1 2023/3/22 16/59/59 1 麻婆豆腐 2 2 2 油淋生菜 1 3 1 delete end

table 1: 1 麻婆豆腐 36 2 油淋生菜 27 table 1 out of opening hours

麻婆豆腐 12 油淋生菜 9 table 1 2022/12/5 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣鸡丝 1 2 5 delete 7 delete table 2 2022/12/3 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣鸡丝 1 2 7 delete end

table 1: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣鸡丝 does not exist delete error; delete error; table 2: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣鸡丝 does not exist delete error; table 1 out of opening hours table 2: 63

麻婆豆腐 12 油淋生菜 9 table 1 2022/12/3 19/5/12 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣鸡丝 1 2 table 2 2022/12/3 15/03/02 1 麻婆豆腐 2 2 2 油淋生菜 1 3 3 麻辣鸡丝 1 2 1 4 麻婆豆腐 1 1 7 delete end

table 1: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣鸡丝 does not exist table 2: 1 麻婆豆腐 36 2 油淋生菜 27 麻辣鸡丝 does not exist 4 table 2 pay for table 1 12 delete error; table 1: 63 table 2: 75
分析:
这道题是这个题目集里最难的,当时自己也是听别人说我才知道,而且我写这次作业拖拉了,以前也有点拖拉,但这次题目比以前难所以也就没写完,而且只是看了下题目,稍做了思考而已,这次问题还是出在自己身上,知难而退而且拖拉,望下次改正。
改进建议:
以后pta尽量不再拖拉,争取早点写完。
7-2 有重复的数据
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。
你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES
”这三个字母;如果没有,则输出“NO
”。
输入格式:
你的程序首先会读到一个正整数n,n∈[1,100000],然后是n个整数。
输出格式:
如果这些整数中存在重复的,就输出:
YES
否则,就输出:
NO
输入样例:
5
1 2 3 1 4
输出样例:
YES
源码如下:

import java.util.Scanner; import java.util.Arrays; public class Main{ public static void main(String[] args){ Scanner input=new Scanner(System.in); int n=input.nextInt(); int a[]=new int[n]; int flag=0; for(int i=0;i<n;i++) a[i]=input.nextInt(); Arrays.sort(a); for(int i=0;i<n;i++){ flag=0; int max=n-1,min=0; for(;max>=min;){ int mid=(max+min)/2; if(a[mid]==a[i]&&mid!=i){ flag=1; break; } else if(a[mid]>a[i]){ max=mid-1; } else { min=mid+1; } } if(flag==1)break; } if(flag==0||n==1){ System.out.print("NO"); } else{ System.out.print("YES"); } } }
设计与分析:
这道题和之前pta的一道题一模一样,但上次因为两个很慢的测试点我没有全对,但这次全对了,用的是二分法,但也同样是出了点问题后来改对了。
这里的问题出在判断两数相等时没有设置条件防止最后一次判断时只剩一个数要判断的情况,自己用二分法也用的不多不够熟练,自己输了几组数进去才发现这个问题,改了这个就对了。
踩坑心得:
在使用二分法时应注意自己有没有用错,对于一些这样的数学方法应该多仔细思考检查。
改进建议:
还可用一些其他更快的数学算法,但使用时要仔细。
从键盘录入一段英文文本(句子之间的标点符号只包括“,”或“.”,单词之间、单词与标点之间都以" "分割。
要求:按照每个单词的长度由高到低输出各个单词(重复单词只输出一次),如果单词长度相同,则按照单词的首字母顺序(不区分大小写,首字母相同的比较第二个字母,以此类推)升序输出。
输入格式:
一段英文文本。
输出格式:
按照题目要求输出的各个单词(每个单词一行)。
输入样例:
Hello, I am a student from China.
输出样例:
student
China
Hello
from
am
a
I
源码如下:

import java.util.Scanner; import java.util.ArrayList; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String text = input.nextLine(); String word = ""; ArrayList<String> wordList = new ArrayList<>(); for(int i = 0;i < text.length();i ++){ if(text.charAt(i) == ' '){ wordList.add(word); word = ""; i ++; } if(text.charAt(i) == ',' || text.charAt(i) == '.'){ wordList.add(word); word = ""; if(i == text.length() - 1){ break; } i = i + 2; } word += text.charAt(i); } for(int i = 0;i < wordList.size();i ++){ for(int j = 0;j < wordList.size() - i - 1;j ++){ if(wordList.get(j).length() < wordList.get(j + 1).length()){ String Word = wordList.get(j); wordList.set(j,wordList.get(j + 1)); wordList.set(j + 1,Word); } if(wordList.get(j).length()==wordList.get(j + 1).length()) { for(int k = 0;;k ++) { if(k == wordList.get(j).length()) break; if(wordList.get(j).toLowerCase().charAt(k) > wordList.get(j+1).toLowerCase().charAt(k)) { String Word=wordList.get(j); wordList.set(j,wordList.get(j + 1)); wordList.set(j + 1,Word); break; } if(wordList.get(j).toLowerCase().charAt(k) < wordList.get(j+1).toLowerCase().charAt(k))break; } } } } int flag = 0; for(int i = 0;i < wordList.size();i ++){ flag = 0; for(int j = i - 1;j >= 0;j--){ if(wordList.get(i).equals(wordList.get(j))){ flag = 1; break; } } if(flag == 0) System.out.println(wordList.get(i)); } } }
设计与分析:
这题我是先把所有文本读进去之后在对其处理的,用了Arraylist,设置循环识别每个单词并分开存进Arraylist,在设置循环使用冒泡法对每个单词长度字母对比后再排序,最后输出Arraylist中的元素。
踩坑心得:
这道题好像看着不难,但我花的时间有点多,因为在冒泡排序那里总出问题,测试点过不了,主要还是逻辑上的问题,比如排序相似度比较高的几个单词的情况,后来也是读程序,带了几个例子进去才发现问题并改正。小问题是没看到相同单词输出一次的要求。以后读题还是要仔细,逻辑问题不能急要静下心来慢慢调试。
冒泡排序长度相等时的逻辑问题改前:
改后:
当判断到相同字母时应该直接不用管,只有在字母不同时才处理并break
改进建议:
分开单词可以用split方法结合正则表达式,这样会简单一点。
题目集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且输入均有效,输出格式如下:
天数值
输入样例1:
在这里给出一组输入。例如:
3 2014 2 14 2020 6 14
输出样例1:
在这里给出相应的输出。例如:
2312
输入样例2:
在这里给出一组输入。例如:
2 1935 2 17 125340
输出样例2:
在这里给出相应的输出。例如:
1591-12-17
输入样例3:
在这里给出一组输入。例如:
1 1999 3 28 6543
输出样例3:
在这里给出相应的输出。例如:
2017-2-24
输入样例4:
在这里给出一组输入。例如:
0 2000 5 12 30
输出样例4:
在这里给出相应的输出。例如:
Wrong Format
源码如下:

import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new Scanner(System.in); int year = 0; int month = 0; int day = 0; int choice = input.nextInt(); if (choice == 1) { // test getNextNDays method int m = 0; 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); } m = input.nextInt(); if (m < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.println(date.getNextNDays(m).showDate()); } else if (choice == 2) { // test getPreviousNDays method int n = 0; 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.println(date.getPreviousNDays(n).showDate()); } else if (choice == 3) { //test getDaysofDates method 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(fromDate.getDaysofDates(toDate)); } else { System.out.println("Wrong Format"); System.exit(0); } } else { System.out.println("Wrong Format"); System.exit(0); } } } class DateUtil { private Day day; public DateUtil() { super(); } public DateUtil(int d,int m, int y) { this.day = new Day(d,m,y); } public Day getDay() { return day; } public void setDay(Day day) { this.day = day; } public boolean checkInputValidity() { if(day.validate()) { return true; } else return false; } public boolean compareDates(DateUtil date) { if(day.getMonth().getYear().getValue() == date.day.getMonth().getYear().getValue()){//先判断年 if(day.getMonth().getValue() == date.day.getMonth().getValue()){//再判断月 if(day.getValue() > date.day.getValue())//最后判断日 return true; else return false; } else if(day.getMonth().getValue() > date.day.getMonth().getValue()){ return true; } else return false; } else if(day.getMonth().getYear().getValue() > date.day.getMonth().getYear().getValue()){ return true; } else return false; } public boolean equalTwoDates(DateUtil date) { if(day.getMonth().getYear().getValue() == date.day.getMonth().getYear().getValue() &&day.getMonth().getValue() == date.day.getMonth().getValue()&&day.getValue() == date.getDay().getValue()) return true; else return false; } public String showDate() { return (day.getMonth().getYear().getValue()+"-"+day.getMonth().getValue()+"-"+day.getValue()); } public DateUtil getNextNDays(int n) { for(;n>0;){ day.dayIncrement(); n--; } DateUtil date1=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); return date1; } public DateUtil getPreviousNDays(int n){ for(;n>0;){ day.dayReduction(); n--; } DateUtil date1=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); return date1; } public int getDaysofDates(DateUtil date){ int gap=0; if(!compareDates(date)){ for(;!equalTwoDates(date);){//相等时结束gap等于间隔天数 day.dayIncrement(); gap++; } } else { for(;!equalTwoDates(date);){ date.day.dayIncrement(); gap++; } } return gap; } } class Year { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Year(int value) { super(); this.value = value; } public Year() { super(); // TODO Auto-generated constructor stub } public void yearIncrement() { value ++; } public void yearReduction() { value --; } public boolean isLeapYear() { if(value%400==0||value%4==0&&value%100!=0) return true; else return false; } public boolean validate() { if(value>=1900&&value<=2050) return true; else return false; } } class Month { private Year year; private int value; public Year getYear() { return year; } public void setYear(Year year) { this.year = year; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month() { super(); // TODO Auto-generated constructor stub } public Month(int yearValue, int monthValue) { super(); this.year = new Year(yearValue); this.value = monthValue; } public void resetMin() { year.yearIncrement(); value = 1; } public void resetMax() { year.yearReduction(); value = 12; } public boolean validate() { if(year.validate()) { if(value >= 1 && value <= 12) return true; else return false; } else return false; } public void monthIncrement() { if(value < 12) value ++; else { resetMin(); } } public void monthReduction() { if(value == 1) { resetMax(); } else { value --; } } } class Day { private int value; private Month month; private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month getMonth() { return month; } public void setMonth(Month value) { this.month = value; } public Day() { super(); // TODO Auto-generated constructor stub } public Day(int yearValue, int monthValue, int dayValue) { super(); this.value = dayValue; this.month = new Month(yearValue,monthValue); } public void resetMin() { month.monthIncrement(); value = 1; } public void resetMax() { month.monthReduction(); if(month.getYear().isLeapYear()&&month.getValue() == 2)//闰年二月特殊处理 value = 29; else value = mon_maxnum[month.getValue()-1]; } public boolean validate() { if(month.validate()) { if(month.getYear().isLeapYear() && month.getValue() == 2){ if(value <= 29 && month.validate()) return true; else return false; } else { if(value <= mon_maxnum[month.getValue() - 1]) return true; else return false; } } else return false; } public void dayIncrement() { if(month.getYear().isLeapYear() && month.getValue() == 2) {//闰年二月特殊处理其他照常 if(value < 29) { value ++; } else { resetMin(); } } else { if(value < mon_maxnum[month.getValue() - 1]) { value ++; } else { resetMin(); } } } public void dayReduction() { if(value == 1) { resetMax(); } else value --; } }
设计与分析:
类图:
自己按照类图把所有方法都实现了,知道了value就是对应类的时间值,在此理解上实现了功能,但最后题目要求的聚合没有实现,自己类图上是关联关系。通过题目的图可以看出各个类之间的关系,在调year或者month类的方法不能直接和DateUtil类打交道,应该通过其他类间接调用环环相扣。
踩坑心得:
尽管功能实现了,但是类间关系没有对,要多思考类间关系的实现。
改进建议:
多思考,改成聚合
参考题目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:值
输入样例1:
在这里给出一组输入。例如:
3 2014 2 14 2020 6 14
输出样例1:
在这里给出相应的输出。例如:
The days between 2014-2-14 and 2020-6-14 are:2312
输入样例2:
在这里给出一组输入。例如:
2 1834 2 17 7821
输出样例2:
在这里给出相应的输出。例如:
1834-2-17 previous 7821 days is:1812-9-19
输入样例3:
在这里给出一组输入。例如:
1 1999 3 28 6543
输出样例3:
在这里给出相应的输出。例如:
1999-3-28 next 6543 days is:2017-2-24
输入样例4:
在这里给出一组输入。例如:
0 2000 5 12 30
输出样例4:
在这里给出相应的输出。例如:
Wrong Format
源码如下:

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int year = 0; int month = 0; int day = 0; int choice = input.nextInt(); if (choice == 1) { // test getNextNDays method int m = 0; 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); } m = input.nextInt(); if (m < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print(date.getYear().getValue()+ "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " next " + m + " days is:"); System.out.println(date.getNextNDays(m).showDate()); } else if (choice == 2) { // test getPreviousNDays method int n = 0; 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( date.getYear().getValue() + "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " previous " + n + " days is:"); System.out.println(date.getPreviousNDays(n).showDate()); } else if (choice == 3) { //test getDaysofDates method 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 DateUtil { private Year year; private Month month; private Day day; private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31}; 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 DateUtil() { super(); // TODO Auto-generated constructor stub } public DateUtil(int y, int m, int d) { super(); year = new Year(y); month = new Month(m); day = new Day(d); } public boolean checkInputValidity() { if(year.getValue() <= 2020 && year.getValue() >= 1820 &&month.getValue() >= 1 && month.getValue() <= 12 && day.getValue() >= 1){ if(year.isLeapYear() && month.getValue() == 2){ if(day.getValue() <= 29) return true; else return false; } else if(day.getValue() <= mon_maxnum[month.getValue() - 1]) return true; else return false; } else return false; } public boolean compareDates(DateUtil date) { if(year.getValue() == date.year.getValue()){ if(month.getValue() == date.month.getValue()){ if(day.getValue() > date.day.getValue()) return true; else return false; } else if(month.getValue() > date.month.getValue()){ return true; } else return false; } else if(year.getValue() > date.year.getValue()){ return true; } else return false; } public boolean equalTwoDates(DateUtil date) { if(year.getValue() == date.year.getValue() &&month.getValue() == date.month.getValue() &&day.getValue() == date.getDay().getValue()) return true; else return false; } public String showDate() { return (year.getValue()+"-"+month.getValue()+"-"+day.getValue()); } public void setDayMin() { if(month.getValue() < 12) month.monthIncrement(); else { year.yearIncrement(); month.setValue(1); } day.setValue(1); } public void setDayMax() { if(month.getValue() == 1) { year.yearReduction();; month.setValue(12); } else { month.monthReduction(); } if(year.isLeapYear() && month.getValue() == 2) day.setValue(29); else day.setValue(mon_maxnum[month.getValue() - 1]); } public DateUtil getNextNDays(int n) { for(;n > 0;){ if(year.isLeapYear() && month.getValue() == 2) { if(day.getValue() < 29) { day.dayIncrement(); } else { setDayMin(); } } else { if(day.getValue() < mon_maxnum[month.getValue() - 1]) { day.dayIncrement(); } else { setDayMin(); } } n--; } DateUtil date1 = new DateUtil(year.getValue(),month.getValue(),day.getValue()); return date1; } public DateUtil getPreviousNDays(int n){ for(;n > 0;){ if(day.getValue() == 1) { setDayMax(); } else day.dayReduction(); n --; } DateUtil date1 = new DateUtil(year.getValue(),month.getValue(),day.getValue()); return date1; } public int getDaysofDates(DateUtil date){ int gap = 0; if(!compareDates(date)){ for(;!equalTwoDates(date);){ if(year.isLeapYear() && month.getValue() == 2) { if(day.getValue() < 29) { day.dayIncrement(); } else { setDayMin(); } } else { if(day.getValue() < mon_maxnum[month.getValue() - 1]) { day.dayIncrement(); } else { setDayMin(); } } gap ++; } } else { for(;!equalTwoDates(date);){ if(day.getValue() == 1) { setDayMax(); } else day.dayReduction(); gap ++; } } return gap; } } class Year { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Year(int value) { super(); this.value = value; } public Year() { super(); // TODO Auto-generated constructor stub } public void yearIncrement() { value ++; } public void yearReduction() { value --; } public boolean isLeapYear() { if(value % 400 == 0 || value % 4 == 0 && value % 100 != 0) return true; else return false; } } class Month { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month() { super(); // TODO Auto-generated constructor stub } public Month(int Value) { super(); this.value = Value; } public void resetMin() { value = 1; } public void resetMax() { value = 12; } public void monthIncrement() { if(value < 12) value ++; else { resetMin(); } } public void monthReduction() { if(value == 1) { resetMax(); } else { value --; } } } class Day { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Day() { super(); // TODO Auto-generated constructor stub } public Day(int Value) { super(); this.value = Value; } public void dayIncrement() { value ++; } public void dayReduction() { value --; } }
设计与分析:
源码类图:
本题除了类之间的关系大体与上题相同,也更符合日期类的设计,想要调year month day 的方法可在DateUtil直接调了,在上题基础上加以修改差不多就对了,但是看自己的类图依旧没有和要求一样类与类聚合。
踩坑心得:
与上题一样还是要多在类间关系上下功夫。
改进建议:
同上题
题目集6
7-1 菜单计价程序-4

本体大部分内容与菜单计价程序-3相同,增加的部分用加粗文字进行了标注。 设计点菜计价程序,根据输入的信息,计算并输出总价格。 输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。 菜单由一条或多条菜品记录组成,每条记录一行 每条菜品记录包含:菜名、基础价格 两个信息。 订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。 桌号标识独占一行,包含两个信息:桌号、时间。 桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。 点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。 不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。 删除记录格式:序号 delete 标识删除对应序号的那条点菜记录。 如果序号不对,输出"delete error" 代点菜信息包含:桌号 序号 菜品名称 份额 分数 代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。 程序最后按输入的桌号从小到大的顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。 每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。 折扣的计算方法(注:以下时间段均按闭区间计算): 周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。 周末全价,营业时间:9:30-21:30 如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours" 参考以下类的模板进行设计(本内容与计价程序之前相同,其他类根据需要自行定义): 菜品类:对应菜谱上一道菜的信息。 Dish { String name;//菜品名称 int unit_price; //单价 int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) } 菜谱类:对应菜谱,包含饭店提供的所有菜的信息。 Menu { Dish[] dishs ;//菜品数组,保存所有菜品信息 Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。 Dish addDish(String dishName,int unit_price)//添加一道菜品信息 } 点菜记录类:保存订单上的一道菜品记录 Record { int orderNum;//序号 Dish d;//菜品\\ int portion;//份额(1/2/3代表小/中/大份) int getPrice()//计价,计算本条记录的价格 } 订单类:保存用户点的所有菜的信息。 Order { Record[] records;//保存订单上每一道的记录 int getTotalPrice()//计算订单的总价 Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。 delARecordByOrderNum(int orderNum)//根据序号删除一条记录 findRecordByNum(int orderNum)//根据序号查找一条记录 } 本次课题比菜单计价系列-3增加的异常情况: 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”,该条记录认为是错误记录,后面所有的信息并入上一桌一起计算。 本次作业比菜单计价系列-3增加的功能: 菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+基础价格+"T" 例如:麻婆豆腐 9 T 菜价的计算方法: 周一至周五 7折, 周末全价。 注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价: 计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。 最后将所有记录的菜价累加得到整桌菜的价格。 输入格式: 桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS) 菜品记录格式: 菜名+英文空格+基础价格 如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。 点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。 删除记录格式:序号 +英文空格+delete 代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数 最后一条记录以“end”结束。 输出格式: 按输入顺序输出每一桌的订单记录处理信息,包括: 1、桌号,格式:table+英文空格+桌号+”:” 2、按顺序输出当前这一桌每条订单记录的处理信息, 每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名 如果删除记录的序号不存在,则输出“delete error” 最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价 输入样例: 在这里给出一组输入。例如: 麻婆豆腐 12 油淋生菜 9 T table 31 2023/2/1 14/20/00 1 麻婆豆腐 1 16 2 油淋生菜 1 2 2 delete 2 delete end 输出样例: 在这里给出相应的输出。例如: table 31: 1 num out of range 16 2 油淋生菜 18 deduplication 2 table 31: 0 0 输入样例1: 份数超出范围+份额超出范围。例如: 麻婆豆腐 12 油淋生菜 9 T table 31 2023/2/1 14/20/00 1 麻婆豆腐 1 16 2 油淋生菜 4 2 end 输出样例1: 份数超出范围+份额超出范围。例如: table 31: 1 num out of range 16 2 portion out of range 4 table 31: 0 0 输入样例2: 桌号信息错误。例如: 麻婆豆腐 12 油淋生菜 9 T table a 2023/3/15 12/00/00 1 麻婆豆腐 1 1 2 油淋生菜 2 1 end 输出样例2: 在这里给出相应的输出。例如: wrong format 输入样例3: 混合错误:桌号信息格式错误+混合的菜谱信息(菜谱信息忽略)。例如: 麻婆豆腐 12 油淋生菜 9 T table 55 2023/3/31 12/000/00 麻辣香锅 15 1 麻婆豆腐 1 1 2 油淋生菜 2 1 end 输出样例3: 在这里给出相应的输出。例如: wrong format 输入样例4: 错误的菜谱记录。例如: 麻婆豆腐 12.0 油淋生菜 9 T table 55 2023/3/31 12/00/00 麻辣香锅 15 1 麻婆豆腐 1 1 2 油淋生菜 2 1 end 输出样例4: 在这里给出相应的输出。例如: wrong format table 55: invalid dish 麻婆豆腐 does not exist 2 油淋生菜 14 table 55: 14 10 输入样例5: 桌号格式错误(以“table”开头)+订单格式错误(忽略)。例如: 麻婆豆腐 12 油淋生菜 9 T table a 2023/3/15 12/00/00 1 麻婆 豆腐 1 1 2 油淋生菜 2 1 end 输出样例5: 在这里给出相应的输出。例如: wrong format 输入样例6: 桌号格式错误,不以“table”开头。例如: 麻婆豆腐 12 油淋生菜 9 T table 1 2023/3/15 12/00/00 1 麻婆豆腐 1 1 2 油淋生菜 2 1 tab le 2 2023/3/15 12/00/00 1 麻婆豆腐 1 1 2 油淋生菜 2 1 end 输出样例6: 在这里给出相应的输出。例如: table 1: 1 麻婆豆腐 12 2 油淋生菜 14 wrong format record serial number sequence error record serial number sequence error table 1: 26 17 其他用例请参考公开的测试用例
设计与分析:
这题和菜单计价程序-3的情况差不多,先是看到太难了,后来看到也没什么人写,也有偷懒的想法,前两天没怎么动,知难而退了属于,到最后两三天才开始动,所以结果当然是写不完,问题主要还是出现在自己,而且这个难度比以前有几届都下降了,所以更要反思自己的问题加以改正。
3、总结:
这三次作业相对于上次难度显著提升,自己的表现也不好,主要的问题是出现在自己身上,习惯不太好,从大学以来就太过放松自己,以后应该多收收心,不能混日子过,把学业看得更重。以后写pta一定要尽早完成,不能知难而退,以后只会越来越难,必须要抓紧时间来提升自己才能学好这门课。这三次作业主要涉及的是类与对象,正则表达式以及一部分字符串的知识,对于功能上的实现基本能做到但是细化到类与类的关系就不太行,以后应该多往这方面提升,尽量写出更加规范的代码来实现功能,这次也加深了一些类与对象的理解,还是要在做题中学习计算机语言。