前言
题目集4:主要涉及知识点为字符串的排序、删除---字符串的各种方法的使用(例如charAT--获取字符,subString--提取子串等),字符串中ArrayList<String>textList=new ArrayList<>()//引用ArrayList方法,封装性、Scanner类中nextLine()等方法、String类中split()等方法、Integer类中parseInt()等方法的用法,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位的用法,其中还有一道为菜单类题目,涉及类与类的联系的问题;本次题目集题量还行,但难度偏大;
题目集5:本次题目集涉及正则表达式的应用;以及日期问题面向对象设计(聚合一)、(聚合二),在前几次的日期类涉及题目的基础上扩展,引入了类的的引用(DateUtil、Year、Month、Day),对类的封装以及调用封装类中的属性以及类中方法的调用进行考察;本次题目集共6道,其中前四天题为正则表达式范围内的类题,第五第六分别为开放性与封装性的日期类日期问题,前四题难度较小,后两题难度较大;
题目集6:本次题目集由于是系统的建立因此其中的功能涉及多个维度包括时间、数组、字符。其中不仅要不断的去完成各个类中功能设计,同时还要清楚各个类之间的联系与调用,其中日期类问题考察了包括Calender类和data类的使用,数组包括字符数组也包括整形数组,要求运用split的方法和while循环,在一定的程度上也同样考察了对matches的运用和正则表达式的表示规律等Java知识;本次题目集只有一个菜单类题,但题目难度特别大,涉及特别广,而且代码量特大,对学生要求很高;
设计与分析
7-1 菜单计价程序-3
该菜单程序题目主要点菜功能,当然有点菜则必然有菜谱,同时要判断菜品的存在性,该程序不仅要实现基本的点菜功能,还有删除和输出点菜记录的功能,同时蕴含着桌的概念和代点菜的功能,不仅有点菜时间和折扣价,同时需要通过点菜时间去判断是否在营业时间,如果为折扣时间还要做出对价格的折扣;
该题的思路大概理清楚了,但是由于当时在题目集4时对7-2,7-3,7-4上花费时间太长,导致代码简略写到完后发现在eclipse上无法运行,会出现空指针java.lang.NullPointerException: Cannot read field "******" because "******" is null。的情况,同时没有做到功能与类全部完善,故没有复制至pta而得0分;
题目集4 7-2 有重复数据
该题的给予内存很小,在寻常的for循环输入与for循环输出下会一直出现运行超时的情况,在投机取巧的方式下,我借用Array的Java类报中Array.sort()的方法以一种概率性的方式通过了测试点;
我的代码如下:
import java.util.Arrays; import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); int i=0,j=0; int flag=0; int n=in.nextInt(); int[] num=new int[n]; for(i=0;i<n;i++){ num[i]=in.nextInt(); } Arrays.sort(num); for(j=1;j<n-1;j++){ if(num[j+1]==num[j]||num[j-1]==num[j]){ flag=1; break; } } if(flag==0||n==1){ System.out.println("NO"); } else{ System.out.println("YES"); } } }View Code
圈复杂度如下:
但这明显是存在纰漏的,在向其他同学请教后,发现可以借用HashSet类包的方法自动排序可以实现代码;
题目集4 7-3 去掉重复数据
该题在7-2去掉重复数据的基础上添加了去除数据的功能,引用上述的代码发现一直会运行超时,思考许久都没有解决方法,本来已经打算放弃,但发现室友已经写出便跑去询问他的思路,发现可以使用房间的思维方式去处理这100000的数据,通过占用的思想能够有效剪断运行时间;
代码如下:
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); int[] num=new int[100001];//限度范围; int n=in.nextInt(); for(int i=0;i<n;i++){//进行n次循环输入; int number=in.nextInt(); if(num[number]==0){ num[number]++;//作为判断依据,证明num[number]没有重复输入; if(i!=0){ System.out.print(" "+number);//当补位不为最后一次输入时,输出要加“ ”; } else System.out.print(number); } if(num[number]==1){//证明已存在该数字; continue; } } } }View Code
该方法属于另辟蹊径,通过数组的方式去了相关的查找和删除;
但可以用Hashset类包(是Set集合的一个实现,具有set集合不重复的特点,同时具有可预测的迭代顺序,也就是我们插入的顺序)与Iterator(Java迭代器(Iterator)是 Java 集合框架中的一种机制,它提供了一种在不暴露集合内部实现的情况下遍历集合元素的方法)类包解决;
import java.util.Scanner; import java.util.LinkedHashSet; import java.util.Iterator; public class Main{ public static void main(String[] args){ LinkedHashSet List = new LinkedHashSet(); Scanner input=new Scanner(System.in); int n=input.nextInt(); for(int i=0;i<n;i++){ List.add(input.nextInt()); } int i = 0; for(Iterator output = List.iterator();output.hasNext();) { System.out.print(output.next()); i++; if(i != List.size())System.out.print(" "); } } }
7-4 单词统计与排序
该题应用到了 ArrayList<String>textList=new ArrayList<>()的方法,对该题重复单词只输出一次,我原本的思路是先排序后去去重,结果却总是差强人意,但后来发现可以在输出时就通过ArraryList方法的特殊性进行查重 if(str.charAt(i)==','||str.charAt(i)=='.'){
int flag=0;
for(int j=0;j<textList.size();j++){//查询已经截取的字符串里是否含相同字符串,相同则不取;
if(textList.get(j).equals(text)){
flag=1;
break;
}
}
if(flag==0){
textList.add(text); //不存在就加入;
}
当已截取的字符串没有该字符时就将其加入其中,有则不加入,做到去重的效果;
7-5 日期问题面向对象设计(聚合一)
该日期类题目在前几次的迭代下新引入了类的概念,
题目要求类图如下:在题目要求的类图下完成以下代码:
Day类代码如下:
class Day{ private int value; private Month month; int mon[]= {0,31,28,31,30,31,30,31,31,30,31,30,31}; public Day() { } public Day(int yearValue,int monthValue,int dayValue){ this.month=new Month(yearValue,monthValue); this.value=dayValue; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Month getMonth() { return month; } public void setMonth(Month month) { this.month=month; } public void resetMin() { value=1; } public void resetMax(){ if(month.getYear().isLeapYear()) { mon[2]=29; } value=mon[month.getValue()]; } public boolean vaildate() { if(month.getYear().isLeapYear()) { mon[2]=29; } if(value>0&&value<=mon[month.getValue()]) { return true; } else { return false; } }//日是否合法 public void monthincrement() { this.value=this.value+1; } public void monthReduction() { this.value=this.value-1; } }View Code
Month类代码如下:
class Month{ private int value; private Year year; public Month(){ } public Month(int yearValue,int monthValue){ this.year=new Year(yearValue); this.value=monthValue; } public int getValue(){ return value; } void setValue(int value) { this.value=value; } public Year getYear() { return year; } void setYear(Year year) { this.year=year; } public void resetMin() { value=1; } public void resetMax(){ value=12; } public boolean validate() { if(value>0&&value<13) { return true; } else { return false; } }//月份是否合法 public void monthincrement() { this.value=this.value+1; } public void monthReduction() { this.value=this.value-1; } }View Code
Year类代码如下:
class Year{ private int value; public Year(){ } public Year(int yearValue){ this.value=yearValue; } public int getValue(){ return value; } public void setValue(int value){ this.value=value; }//赋值方法 public boolean isLeapYear(){ if(value%4==0){ if(value%100==0){ if(value%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } }//判断是否为闰年 public boolean isLeapYear(int value){ if(value%4==0){ if(value%100==0){ if(value%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } }//带参数判断是否为闰年 public boolean validate(){ if(value>=1900&&value<=2050){ return true; } else { return false; } } public void yearincrement() { this.value=this.value+1; } public void yearReduction() { this.value=this.value-1; } }//年份是否合法;View Code
DateUtil类代码如下:
class DateUtil{ private Day day; public DateUtil(){ } 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(getDay().getMonth().getYear().validate()&&getDay().getMonth().validate()&&getDay().vaildate()) { return true; } else { return false; } }//判断日期是否合理 public boolean equalTwoDates(DateUtil date){ if(date.getDay().getValue()==day.getValue()&date.day.getMonth().getYear().getValue()==day.getMonth().getYear().getValue()&&date.day.getMonth().getValue()==day.getMonth().getValue()){ return true; } else{ return false; } }//判断两日期是否相等 public boolean compareDates(DateUtil date){ if(equalTwoDates(date)==false) { if(date.getDay().getMonth().getYear().getValue()>getDay().getMonth().getYear().getValue()){//年不等 return true; } else if(date.day.getMonth().getYear().getValue()==day.getMonth().getYear().getValue()&&date.day.getMonth().getValue()>day.getMonth().getValue()){//年等月不等 return true; } else if(date.day.getMonth().getYear().getValue()==day.getMonth().getYear().getValue()&&date.day.getMonth().getValue()==day.getMonth().getValue()&&date.getDay().getValue()>getDay().getValue()){ return true; }//年月都等,日不等 else{ return false; } } else { return false; } }//比较两日期谁先谁后 public DateUtil getNextNDays(int n){ while(n>365) { if(day.getMonth().getYear().isLeapYear()==true&&day.getMonth().getValue()<=2){ n=n-366; day.getMonth().getYear().yearincrement(); } else if(day.getMonth().getYear().isLeapYear(day.getMonth().getYear().getValue()+1)==true&&day.getMonth().getValue()>2){ n=n-366; day.getMonth().getYear().yearincrement();; } else{ n=n-365; day.getMonth().getYear().yearincrement();; } }//将n范围限制在365天内 if(day.getMonth().getYear().isLeapYear()==true){ day.mon[2]=29; }//判断变化后年是否为闰年 if((n-day.mon[day.getMonth().getValue()]+day.getValue()-1)>=0){ n=n-day.mon[day.getMonth().getValue()]+day.getValue()-1; day.resetMin();//将日重置为1,方便后续计算 day.getMonth().monthincrement();//月份加一 if(day.getMonth().getValue()>12){ day.getMonth().resetMin(); day.getMonth().getYear().yearincrement(); }//年份加一 while(n>=day.mon[day.getMonth().getValue()]){ if(day.getMonth().getYear().isLeapYear()==true){ day.mon[2]=29; } n-=day.mon[day.getMonth().getValue()]; day.getMonth().monthincrement(); if(day.getMonth().getValue()==13){ day.getMonth().resetMin();; day.getMonth().getYear().yearincrement(); } }//如果n仍大于这月的天数,则循环 day.setValue(n+1); } else{ day.setValue(day.getValue()+n); } DateUtil newday=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); return newday;//返回n天后的日期 } //下n天 public DateUtil getPreviousNDays(int n){ while(n>365) { if(day.getMonth().getYear().isLeapYear()==true&&day.getMonth().getValue()>2){ n=n-366; day.getMonth().getYear().yearReduction(); } else if(day.getMonth().getYear().isLeapYear(day.getMonth().getYear().getValue()-1)==true&&day.getMonth().getValue()<=2){ n=n-366; day.getMonth().getYear().yearReduction(); } else{ n=n-365; day.getMonth().getYear().yearReduction(); } }//将n限制在365天内 if(day.getMonth().getYear().isLeapYear()==true){ day.mon[2]=29; } if(n-day.getValue()+1>=0){ n=n-day.getValue()+1;//n减少相应天数 day.resetMin();//将日重置为一 day.getMonth().monthReduction();//月份减一 if(day.getMonth().getValue()<1){ day.getMonth().resetMax(); day.getMonth().getYear().yearReduction(); } while(n>=day.mon[day.getMonth().getValue()]){ if(day.getMonth().getYear().isLeapYear()==true){ day.mon[2]=29; }//判断是否为闰年; n-=day.mon[day.getMonth().getValue()]; day.getMonth().monthReduction(); if(day.getMonth().getValue()==0){ day.getMonth().resetMax(); day.getMonth().getYear().yearReduction(); } }//当n大于当月天数时,循环 day.setValue(day.mon[day.getMonth().getValue()]-n+1);//将剩余的n赋值到day里 } else { day.setValue(day.getValue()-n);//如果一开始就不会超过当月最小天数,直接运算 } DateUtil newday=new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); return newday; } public int getDaysofDates(DateUtil date){ DateUtil d1=this; DateUtil d2=date; int mon[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; if(this.equalTwoDates(date)){//如果两天的日期相等 return 0; } else if(!this.compareDates(date)){//如果日期大小不对且date在this前 d1=date; d2=this; }//交换两日期的值 int i,cha=0; for(i=d1.getDay().getMonth().getYear().getValue()+1;i<d2.getDay().getMonth().getYear().getValue();i++){//两个日期的年份天数和 cha=cha+365; if(new Year(i).isLeapYear())//闰年天数为366天 cha++; } if(d1.getDay().getMonth().getYear().getValue()==d2.getDay().getMonth().getYear().getValue()&&d1.getDay().getMonth().getValue()==d2.getDay().getMonth().getValue()){//年份相同,月份相同,日不同 cha=d2.getDay().getValue()-d1.getDay().getValue(); } else if(d1.getDay().getMonth().getYear().getValue()==d2.getDay().getMonth().getYear().getValue()&&d1.getDay().getMonth().getValue()!=d2.getDay().getMonth().getValue()){//年份相同,月份不同 if(d1.getDay().getMonth().getYear().isLeapYear())//如果该年为是闰年 mon[2]=29; cha=cha+mon[d1.getDay().getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=d1.getDay().getMonth().getValue()+1;i<=d2.getDay().getMonth().getValue()-1;i++)//月份天数和 cha+=mon[i]; } else if(d1.getDay().getMonth().getYear().getValue()!=d2.getDay().getMonth().getYear().getValue()){//年份不同 cha=cha+mon[d1.getDay().getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=d1.getDay().getMonth().getValue()+1;i<=12;i++)//小日期在该年剩余的天数 cha=cha+mon[i]; for(i=d2.getDay().getMonth().getValue()-1;i>0;i--)//大日期在该年已经过的天数 cha=cha+mon[i]; if(d1.getDay().getMonth().getYear().isLeapYear()&&d1.getDay().getMonth().getValue()<=2)//如果小日期该年为闰年且该天在1月或2月,则表示会经过29日的二月 cha++; if(d2.getDay().getMonth().getYear().isLeapYear()&&d2.getDay().getMonth().getValue()>2)//如果大日期该年为闰年且该天在1月或2月后,则表示会经过29日的二月 cha++; } return cha; } public String showdate() { return this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue(); } }View Code
Main类代码如下:
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.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); } } }View Code
代码圈复杂度如下:
发现其中主类比较复杂,估计是在结构上有些逻辑比较混乱;
对这次DateUtil类中方法,为适应此次题目要求,在对上一次的日期类中两日期间隔的方法进行了改动:
1.将日期规定为data在this之后,如果data在this之前,则通过交换两日期实现data在this之后;
2.首先对年之差进行for循环将其加入cha属性中,当year之差下与于2后截止3;
3.接下来分别对月和日之差进行运算,分年相同与年不相同两种情况,年相同自己对月进行相减,当month之差下于2后对月进行判断,当month相同后直接对day之差进行运算,之后进行是否经历闰年的情况,若有,则将差再进行加一处理;
public int getDaysofDates(DateUtil date){ DateUtil d1=this; DateUtil d2=date; int mon[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; if(this.equalTwoDates(date)){//如果两天的日期相等 return 0; } else if(!this.compareDates(date)){//如果日期大小不对且date在this前 d1=date; d2=this; }//交换两日期的值 int i,cha=0; for(i=d1.getDay().getMonth().getYear().getValue()+1;i<d2.getDay().getMonth().getYear().getValue();i++){//两个日期的年份天数和 cha=cha+365; if(new Year(i).isLeapYear())//闰年天数为366天 cha++; } if(d1.getDay().getMonth().getYear().getValue()==d2.getDay().getMonth().getYear().getValue()&&d1.getDay().getMonth().getValue()==d2.getDay().getMonth().getValue()){//年份相同,月份相同,日不同 cha=d2.getDay().getValue()-d1.getDay().getValue(); } else if(d1.getDay().getMonth().getYear().getValue()==d2.getDay().getMonth().getYear().getValue()&&d1.getDay().getMonth().getValue()!=d2.getDay().getMonth().getValue()){//年份相同,月份不同 if(d1.getDay().getMonth().getYear().isLeapYear())//如果该年为是闰年 mon[2]=29; cha=cha+mon[d1.getDay().getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=d1.getDay().getMonth().getValue()+1;i<=d2.getDay().getMonth().getValue()-1;i++)//月份天数和 cha+=mon[i]; } else if(d1.getDay().getMonth().getYear().getValue()!=d2.getDay().getMonth().getYear().getValue()){//年份不同 cha=cha+mon[d1.getDay().getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=d1.getDay().getMonth().getValue()+1;i<=12;i++)//小日期在该年剩余的天数 cha=cha+mon[i]; for(i=d2.getDay().getMonth().getValue()-1;i>0;i--)//大日期在该年已经过的天数 cha=cha+mon[i]; if(d1.getDay().getMonth().getYear().isLeapYear()&&d1.getDay().getMonth().getValue()<=2)//如果小日期该年为闰年且该天在1月或2月,则表示会经过29日的二月 cha++; if(d2.getDay().getMonth().getYear().isLeapYear()&&d2.getDay().getMonth().getValue()>2)//如果大日期该年为闰年且该天在1月或2月后,则表示会经过29日的二月 cha++; } return cha; }
在日判断中由于一时疏忽没有在value<=mon[mon.getValue()处添上等于号故导致一直有一个测试点错误,果然是细节决定成败;
7-6 日期问题面向对象设计(聚合二)
该题在7-5的基础下强化了封装性的概念,并且将原本的聚合关系改变将DateUtil变成了分别与Year、Month、Day聚合,不再向7-5中似的有传递关系;由于聚合关系的变化故而将day类简化,将setDayMax与setDayMin方法以及对日的合法检测放入DateUtil中去,省去day对于Date的调用;其他的思路都与7-5相似,不过都将原本Year、Month中属性的表示方式做了变化,自己重DateUtil中去调用与赋值,使得线程变得更加简单,
代码如下所示:
Day类:
class Day{ private int value; public Day() { } public Day(int dayValue){ this.value=dayValue; } public int getValue() { return value; } public void setValue(int value) { this.value = value; }//对日赋值 public void montIncrement() { this.value=this.value+1; } public void monthReduction() { this.value=this.value-1; } }View Code
Month类:
class Month{ private int value; public Month(){ } public Month(int monthValue){ this.value=monthValue; } public int getValue(){ return value; } void setValue(int value) { this.value=value; }//对月赋值 public void resetMin() { value=1; } public void resetMax(){ value=12; } public boolean validate() { if(value>0&&value<13) { return true; } else { return false; } }//判断月合法性 public void monthIncrement() { this.value=this.value+1; } public void monthReduction() { this.value=this.value-1; } }View Code
Year类:
class Year{ private int value; public Year(){ } public Year(int yearValue){ this.value=yearValue; } public int getValue(){ return value; } public void setValue(int value){ this.value=value; }//对年赋值 public boolean isLeapYear(){ if(value%4==0){ if(value%100==0){ if(value%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } }//判断是否为闰年 public boolean isLeapYear(int value){ if(value%4==0){ if(value%100==0){ if(value%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } }//闰年的有参判断 public boolean validate(){ if(value>=1820&&value<=2020){ return true; } else { return false; } }//判断年是否合法 public void yearIncrement() { this.value=this.value+1; } public void yearReduction() { this.value=this.value-1; } }View Code
DateUtil类:
class DateUtil{ Day day; Month month; Year year; int mon[]= {0,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(){ } public DateUtil(int y,int m,int d){ day=new Day(); month=new Month(); year=new Year(); day.setValue(d); month.setValue(m); year.setValue(y); } public Day getDay() { return day; } public Month getMonth() { return month; } public void setMonth(Month month) { this.month = month; } public Year getYear() { return year; } public void setYear(Year year) { this.year = year; } public void setDay(Day day) { this.day=day; } public void setDayMin() { day.setValue(1); }//重置日为最小 public void DayMax() { if(year.isLeapYear()) { mon[2]=29; } day.setValue(mon[month.getValue()]); }//重置日为最大 public boolean checkInputValidity(){ if(getYear().validate()==true&&getMonth().validate()==true) { if(getYear().isLeapYear()) { mon[2]=29; } if(day.getValue()<=mon[month.getValue()]) return true; else { return false; } } else { return false; } }//检查日期的合法性 public boolean equalTwoDates(DateUtil date){ if(date.getDay().getValue()==day.getValue()&date.year.getValue()==year.getValue()&&date.month.getValue()==month.getValue()){ return true; } else{ return false; } }//比较两日期是否相等 public boolean compareDates(DateUtil date){ if(equalTwoDates(date)==false) { if(date.getYear().getValue()>getYear().getValue()){ return true; }//年不同 else if(date.getYear().getValue()==getYear().getValue()&&date.getMonth().getValue()>getMonth().getValue()){ return true; }//年铜月不同 else if(date.getYear().getValue()==getYear().getValue()&&date.month.getValue()==month.getValue()&&date.getDay().getValue()>getDay().getValue()){ return true; }//年月同日不同 else{ return false; } } else { return false; } }//比较两日期谁在前谁在后 public DateUtil getNextNDays(int n){ while(n>365) { if(year.isLeapYear()==true&&month.getValue()<=2){ n=n-366; getYear().yearIncrement(); }//当当年为闰年,且月小于3,经过366天 else if(getYear().isLeapYear(year.getValue()+1)==true&&month.getValue()>2){ n=n-366; year.yearIncrement();; }//当后一年为闰年,本月大于2,经过366天; else{ n=n-365; year.yearIncrement();; } }//将n限制为365内 if(year.isLeapYear()==true){ mon[2]=29; }//判断是否为闰年 if((n-mon[month.getValue()]+day.getValue()-1)>=0){ n=n-mon[month.getValue()]+day.getValue()-1; setDayMin();//将日重置为1 month.monthIncrement();//月份加一 if(month.getValue()>12){ month.resetMin(); year.yearIncrement(); }//年变化 while(n>=mon[month.getValue()]){ if(year.isLeapYear()==true){ mon[2]=29; } else{ mon[2]=28; } n-=mon[month.getValue()]; month.monthIncrement(); if(month.getValue()==13){ month.resetMin(); year.yearIncrement(); }//年变化 }//n大于当月天数,循环 day.setValue(n+1);//n<当月天数,直接赋值日 } else{ day.setValue(day.getValue()+n);//n加day后不会超过本月天数,直接运算 } DateUtil newday=new DateUtil(year.getValue(),month.getValue(),day.getValue()); return newday; } public DateUtil getPreviousNDays(int n){ while(n>365) { if(year.isLeapYear()==true&&month.getValue()>2){ n=n-366; year.yearReduction(); } else if(year.isLeapYear(year.getValue()-1)==true&&month.getValue()<=2){ n=n-366; year.yearReduction(); } else{ n=n-365; year.yearReduction(); } }//将n限制在365内 if(year.isLeapYear()==true){ mon[2]=29; }//判断是否为闰年 if(n-day.getValue()+1>=0){ n=n-day.getValue()+1;//重置日为一 setDayMin(); month.monthReduction();//月份减一 if(month.getValue()<1){ month.resetMax(); year.yearReduction(); }//年减一 while(n>=mon[month.getValue()]){ if(year.isLeapYear()==true){ mon[2]=29; } else{ mon[2]=28; } n-=mon[month.getValue()]; month.monthReduction(); if(month.getValue()==0){ month.resetMax(); year.yearReduction(); } }//当n大于当月天数,循环 day.setValue(mon[month.getValue()]-n+1);//小于当月天数后直接日变化 } else { day.setValue(day.getValue()-n);//小于当月天数直接日变化 } DateUtil newday=new DateUtil(year.getValue(),month.getValue(),day.getValue()); return newday;//返回n天前的日期 } public int getDaysofDates(DateUtil date){ DateUtil d1=this; DateUtil d2=date; int mon[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; if(this.equalTwoDates(date)){//如果两天的日期相等 return 0; } else if(!this.compareDates(date)){//如果日期大小不对且date在this前 d1=date; d2=this; }//交换两日期的值 int i,cha=0; for(i=d1.getYear().getValue()+1;i<d2.getYear().getValue();i++){//两个日期的年份天数和 cha=cha+365; if(new Year(i).isLeapYear())//闰年天数为366天 cha++; } if(d1.year.getValue()==d2.year.getValue()&&d1.getMonth().getValue()==d2.getMonth().getValue()){//年份相同,月份相同,日不同 cha=d2.getDay().getValue()-d1.getDay().getValue(); } else if(d1.year.getValue()==d2.year.getValue()&&d1.getMonth().getValue()!=d2.getMonth().getValue()){//年份相同,月份不同 if(d1.getYear().isLeapYear())//如果该年为是闰年 mon[2]=29; cha=cha+mon[d1.getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=getMonth().getValue()+1;i<=d2.getMonth().getValue()-1;i++)//月份天数和 cha+=mon[i]; } else if(d1.year.getValue()!=d2.year.getValue()){//年份不同 cha=cha+mon[d1.getMonth().getValue()]-d1.getDay().getValue();//小日期该月剩余的天数,将小日期日化为一,方便后续运算; cha=cha+d2.getDay().getValue();//大日期该月经历的天数,将大日期日化为一,方便后续运算; for(i=d1.getMonth().getValue()+1;i<=12;i++)//小日期在该年剩余的天数 cha=cha+mon[i]; for(i=d2.getMonth().getValue()-1;i>0;i--)//大日期在该年已经过的天数 cha=cha+mon[i]; if(d1.getYear().isLeapYear()&&d1.getMonth().getValue()<=2)//如果小日期该年为闰年且该天在1月或2月 cha++; if(d2.getYear().isLeapYear()&&d2.getMonth().getValue()>2)//如果大日期该年为闰年且该天在1月或2月后 cha++; } return cha; } public String showdate() { return this.getYear().getValue()+"-"+this.getMonth().getValue()+"-"+this.getDay().getValue(); } }View Code
Main类:
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));//输出结果 System.exit(0); }//判断日期是否合法 else{ System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } }View Code
类图如下:
圈复杂程度如下:
对比与7-5中的全复杂度可以看出该题中各类方法的复杂程度都比较低,没有7-5中的数据那么大且幅度大,都比较平稳和小;
由此可以看出两类之间的之间聚合可以使代码的思路和复杂度远小于连续聚合的方式,为以后的设计思路有了不一样的见解;
题目集六:7-1 菜单计价程序-4
该题延续了菜单计价程序-3的设计理念,但是加大了难度,上一次对桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等没做要求,但此次对其做出了相应要求,但由于上次代码没有及时完成,此次在尽量完成上次代码后,发现由于对题目理解错误,在主类中措意了while的方法导致只能记一次桌号,而且由于对此种类与类之间的关系比较复杂的情况不能有很好的经验故在处理问题的过程中没有思路,在很长时间的打磨才完成了一部分代码,本以为可以实现题目所给的测试样例就能有些分,但结果却大相径庭,测试结果如下:
我的代码类图如下:
我的代码如下:
import java.util.Scanner; import java.util.Calendar; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int cntTable=0;//桌号 int[] xu=new int[20]; int q=0; Menu mu = new Menu(); int flag=0; Table[] tablemes = new Table[56]; int j = 0;//菜单数 int l = 0;//订单数 int k = 0;//代点菜数 Dish tt; // sum = 0; int count; String[] temp; int a1,a2,a3,a4,a5; while (true) { String st = in.nextLine(); temp = st.split(" "); if(st.equals("end")) break; count = temp.length; if (count == 2) {//一个空格 //String[] temp1 = st.split(" "); if (temp[1].equals("delete")) {//第二个为delete a1 = Integer.parseInt(temp[0]); if(tablemes[cntTable].odt.findRecordByNum(a1)==null) { System.out.println("deduplication 2"); } else { tablemes[cntTable].odt.delARecordByOrderNum(a1); tablemes[cntTable].sum=tablemes[cntTable].odt.getTotalPrice(); } } else {//菜单添加 if(flag==0) { if(temp[1].matches("[0-9]{1,2}$")) { a2 = Integer.parseInt(temp[1]); if(a2>300||a2<0) { System.out.println(temp[0]+" price out of range "); } else { int ex=0; for(int i=0;i<j;i++) { if(mu.dishs[i].name.equals(temp[0])) { mu.dishs[i] = mu.addDish(temp[0], a2, 0); ex=1; } } if(ex==0) { mu.dishs[j] = mu.addDish(temp[0], a2, 0); j++; } } } else { System.out.println("wrong format"); } } else { System.out.println("invalid dish"); } //continue; } } else if(count==3) { if(flag==0) { if(temp[1].matches("[0-9]{1,2}$")) { a2 = Integer.parseInt(temp[1]); if(a2>300||a2<0) { System.out.println(temp[0]+" price out of range "); } else { int ex=0; for(int i=0;i<j;i++) { if(mu.dishs[i].name.equals(temp[0])) { mu.dishs[i] = mu.addDish(temp[0], a2, 1); ex=1; } } if(ex==0) { mu.dishs[j] = mu.addDish(temp[0], a2, 1); j++; } } } else { System.out.println("wrong format"); } } else { System.out.println("invalid dish"); } } else if (count == 4) {//三个空格 //String[] temp2 = st.split(" "); if (temp[0].equals("table")) {//桌号 if(temp[1].matches("[0-9]{1,2}$")) { cntTable=Integer.parseInt(temp[1]); xu[q]=cntTable; q++; if(cntTable<1||cntTable>55) { System.out.println(cntTable+" table num out of range"); } else { l = 0; tablemes[cntTable] = new Table(); //tablemes[cntTable].tableDtime = st; tablemes[cntTable].AheadProcess(st); if(tablemes[cntTable].f==1) { flag=1; System.out.println("table " + cntTable + ": "); } else { System.out.println("wrong format"); break; } } } else { System.out.println("wrong format"); break; } } else {//增加订单的情况; a3 =Integer.parseInt(temp[0]); a4 = Integer.parseInt(temp[2]); a5=Integer.parseInt(temp[3]); if(a5>15||a5<=0) { System.out.println(a3+" num out of range "+a5); } else if(temp[3].length()==2&&temp[3].charAt(0)=='0') { System.out.println("wrong format"); } else { if(a3>l) { tablemes[cntTable].odt.addARecord(a3, temp[1],a4 , a5); tt = mu.searthDish(temp[1]); if (tt != null) { if(tt.flag==0&&a4>3) { System.out.println(a3+" portion out of range "+a4); } else if(tt.flag==1&&a4!=1&&4!=3) { System.out.println(a3+" portion out of range "+a4); } else { tablemes[cntTable].odt.records[l].d = tt; if(tt.flag==1) { if(tablemes[cntTable].week>1&&tablemes[cntTable].week<6) { int a = tablemes[cntTable].odt.records[l].getPrice(); System.out.println(tablemes[cntTable].odt.records[l].orderNum + " " + tt.name + " " +a ); tablemes[cntTable].sum +=a; } else { int a=Math.round(tablemes[cntTable].odt.records[l].getPrice()*0.7F); System.out.println(tablemes[cntTable].odt.records[l].orderNum + " " + tt.name + " " +a ); tablemes[cntTable].sum +=a; } } else { int a = tablemes[cntTable].odt.records[l].getPrice(); System.out.println(tablemes[cntTable].odt.records[l].orderNum + " " + tt.name + " " +a ); tablemes[cntTable].sum +=a; } } } else { System.out.println(temp[1]+" does not exist"); } l++; } else { System.out.println("record serial number sequence error"); } } } //continue; } else if (count == 5) {//代点菜 //String[] temp3 = st.split(" "); if(temp[0].matches("[0-9]{1,2}$")&&temp[1].matches("[0-9]{1,2}$")&&temp[3].matches("[0-9]{1,2}$")&&temp[4].matches("[0-9]{1,2}$")) { a1 = Integer.parseInt(temp[0]); a2 = Integer.parseInt(temp[1]); a3 = Integer.parseInt(temp[3]); a4 = Integer.parseInt(temp[4]); if(a1>0&&a1<55) { if(mu.searthDish(temp[2])!=null) { if(a2>k) { if((mu.searthDish(temp[2]).flag==1&&a3==1||a3==3)||(mu.searthDish(temp[2]).flag==0&&a3<4&&a3>0)) { if(a4<=15) { if(temp[4].length()==2&&temp[4].charAt(0)=='0') { System.out.println("wrong format"); } else{ tablemes[cntTable].odt.addARecord( a2, temp[2], a3, a4); tt = mu.searthDish(temp[2]); if (tt != null) { int b = tt.unit_price; System.out.println(temp[1] + " table " + tablemes[cntTable].tableNum + " pay for table " + temp[0] + " " + b); tablemes[cntTable].sum += b; } l++; k++; } } else { System.out.println(temp[1]+"num out of range"+temp[4]); } } else if(a3>9) { System.out.println("wrong format"); } else { System.out.println(a2+"portion out of range"+a3); } } else { System.out.println("record serial number sequence error"); } } else { System.out.println(temp[2]+" does not exist"); } } else { System.out.println("Table number :"+a1+" does not exist"); } } else { System.out.println("wrong format"); } } //st = sc.nextLine() else if(count==0){ System.out.println("wrong format"); } else{ System.out.println("wrong format"); } } for(int i=0;i<q;i++) { if(tablemes[xu[i]].f==1) { if(xu[i]!=0) { if(tablemes[xu[i]].discnt>0){ int sum1= Math.round(tablemes[xu[i]].sum*tablemes[xu[i]].discnt); System.out.println("table " +tablemes[xu[i]].tableNum + ": " + tablemes[xu[i]].sum+" "+sum1); } else { System.out.println("table " +tablemes[xu[i]].tableNum + " out of opening hours"); } } } } } } class Dish { String name; int unit_price; //单价 int flag=0; public int getPrice(int portion){//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) int peice=0; if(portion==1) { peice = unit_price; } else if(portion==2) { peice = (int)(unit_price*1.5); } else{ peice = unit_price*2; } return peice; } } class Menu { Dish[] dishs =new Dish[20];//菜品数组,保存所有菜品信息 int count=0; public Dish searthDish(String dishName){ Dish fresh = null; for(int i=0;i<count;i++){ if(dishName.equals(dishs[i].name)){ fresh = dishs[i]; break; } } return fresh; }//根据菜名在菜谱中查找菜品信息,返回Dish对象。 public Dish addDish(String dishName,int unit_price,int flag){ Dish d = new Dish(); d.name = dishName; d.unit_price = unit_price; d.flag=flag; count++; return d; }//添加一道菜品信息 } class Record { int orderNum;//序号 int num; Dish d=new Dish();//菜品\\ int portion;//份额(1/2/3代表小/中/大份) int getPrice(){ return d.getPrice(portion)*num; }//计价,计算本条记录的价格 } class Order { Record[] records=new Record[20];//保存订单上每一道的记录 int count=0; int getTotalPrice(){ int all=0; for(int i=0;i<count;i++) { all+=records[i].getPrice(); } return all; }//计算订单的总价 Record addARecord(int orderNum,String dishName,int portion,int num){ records[count] = new Record(); records[count].d.name = dishName; records[count].orderNum = orderNum; records[count].portion = portion; records[count].num = num; count++; return records[count]; }//添加一条菜品信息到订单中。 public void delARecordByOrderNum(int orderNum){ for(int i=0;i<count;i++) { if(orderNum==records[i].orderNum) { for(int j=i;j<count-1;j++) { records[j]=records[j+1]; } records[count-1]=null; count--; break; } } }//根据序号删除一条记录 public Record findRecordByNum(int orderNum){ Record r=null; for(int i=0;i<count;i++) { if(records[i].orderNum==orderNum) { r = records[i]; } } return r; }//根据序号查找一条记录 } class Table { int tableNum; String tableDtime; int year,month,day,week,hh,mm,ss; int sum = 0;//一桌价格 ; int mon[]= {0,31,28,31,30,31,30,31,31,30,31,30,31}; // boolean f = true; int f=1; Order odt = new Order(); //Order odre = new Order(); float discnt = -1; public boolean validtime() { if(year>=2022&&year<=2023) { if(month>0||month<13) { if(year==2022) { mon[2]=29; } if(day<=mon[month]&&day>0) { return true; } else return false; } else return false; } else return false; } void AheadProcess(String tableDtime){ this.tableDtime = tableDtime; String[] temp = tableDtime.split(" "); String[] temp1 = temp[2].split("/"); year = Integer.parseInt(temp1[0]); month = Integer.parseInt(temp1[1]); day = Integer.parseInt(temp1[2]); if(validtime()==true){ if(hh<24&&hh>=0&&mm>=0&&mm<=60&&ss>=0&&ss<=60) { processTime(); discount(); } else { f=0; } }//CheckAtime(); else{ System.out.println("not a valid time period"); } } void processTime(){//处理时间 String[] temp = tableDtime.split(" "); tableNum = Integer.parseInt(temp[1]); String[] temp1 = temp[2].split("/"); String[] temp2 = temp[3].split("/"); year = Integer.parseInt(temp1[0]); month = Integer.parseInt(temp1[1]); day = Integer.parseInt(temp1[2]); Calendar c = Calendar.getInstance(); c.set(year, (month-1), day); week = c.get(Calendar.DAY_OF_WEEK); if(week==1) week = 7; else week--; hh = Integer.parseInt(temp2[0]); mm = Integer.parseInt(temp2[1]); ss = Integer.parseInt(temp2[2]); } //void CheckAtime(){ // f= !(discnt < 0); // } void discount(){ if(week>5&&week<=7) { if(hh>=10&&hh<=20) discnt= 1.0F; else if(hh==9&&mm>=30) discnt= 1.0F; else if(hh==21&&mm<30||hh==21&&mm==30&&ss==0) discnt= 1.0F; } else { if(hh>=17&&hh<20) discnt=0.8F; else if(hh==20&&mm<30) discnt=0.8F; else if(hh==20&&mm==30&&ss==0) discnt=0.8F; else if(hh==10&&mm>=30||hh>=11&&hh<=13) discnt=0.6F; else if(hh==14&&mm<30) discnt=0.6F; else if(hh==14&&mm==30&&ss==0) discnt=0.6F; } } }View Code
Table类圈复杂度·: Main类:
写到又复杂又达不到效果,真的体现出自己的许多毛病,以后Java学习中要改正态度,认真的改正自己和积累知识以至于不会像这次pta一样无奈;
注意点:
1.题面给了价格计算要四舍五入,简单的强制类型转换不能满足要求。改用Math. round。
2.第一次接触java类的概念。在增加菜品和订单的时候,返回值应是被new 实例化的对象。否则非零返回,会出现。
3.题目要求的是可以进行多个餐桌点单,而非一个点完就跳出程序。
踩坑心得
1.在使用类中的属性或者方法时,务必记得创建对象;同时在创建类的数组,需要使用其元素时也需要对当前元素new一下,否则会报空指针或者非零返回,java.lang.NullPointerException: Cannot read field "******" because "******" is null。
2.题面给了价格计算要四舍五入,简单的强制类型转换不能满足要求。改用Math. round。
3.在类中不能调用属性和方法,只有在方法中才能调用。
总结
一、对Bug的小感悟
bug通常来自几种原因:
1、对题面理解的疏忽,总是没有跟齐题目的思路;
2、对自己代码架构细节出现问题(使用错误方法),并且老是不能及时发现;
3、粗心导致,在面对基础语法和题目要求是总是漏看这忽视那的;
4、知识的缺乏,对一些常用的方法和知识点还是没有很全面的了解;
二、学到的东西
1、熟悉理解了类的设计与使用;
2、对正则表达式的使用;
3、对面向对象编程(封装性)有了初步的认识;
4、积累了许多错误经验,对于常见的报错能够理解、从容的去修改;
5、能够熟练对代码进行调试,查找调试过程中代码的各类数据的变化等;
6、学习到了ArrayList方法的应用和HashSet的一些用法,同时对日期类中Calendar有了初步了解,从此看出java的内容十分精妙并且包涵范围之广;
7.对运行超时有了认识,认识到今后可能会遇到此类问题,要通过对思维的不断扩展以能有更加简洁的想法减少运行时间;
8、同时,对于Java这门语言有了跟多的理解,能够逐渐窥见java面向对象的高明之处;
9、对于Java的学习还是不能够松懈,要跟紧老师的步伐走,同时需要将进度适当提高一些,否则面对大作业就会显得手足无措。
标签:总结,int,pta,getValue,public,第二次,else,day,getMonth From: https://www.cnblogs.com/haidong-liu/p/17356524.html