目录
前言
设计与分析
踩坑心得
改进建议
总结
前言
题目集4题量不多,只有三道,但难度对我来说不太友好,这一次的我只有50分,可想而知它的难度。这次题目集7-1主要涉及字符串处理类以及正则表达式对输入字符串数据进行合法性校验及计算,正则表达式大致会使用,也可能出现了错误,但计算连公式都没看懂,不知道如何计算,最后只能过一个点。而7-2则主要涉及类的聚合,计算前n天、后n天以及两日期之差。7-3则涉及类的继承,定义的图形类继承各自的父类,重写父类中的方法。
题目集5在题目集4的基础上增加了两题,难度也有点下降,前三道都是基础题,主要涉及split的分割和排序,排序包括冒泡、选择、插入的排序和使用Arrays.sort()方法的排序。第四题难度就直线上升,跨度太大,既要提取出Java源码中的关键字,还要统计出现次数并按照关键字升序进行排序输出。该题主要涉及List、Set、Map的接口运用。7-5则是不同于题目集4中7-2的另一种聚合方式,在上次题目集的基础上对算法进行修改,而且这种聚合方式相较上种略微简单。
题目集6题量不大,只有六道,难度也不高,相较之前做起来略微轻松。该题目集主要训练我们正则表达式的使用,还有继承、多态和接口。
设计与分析
①题目集4(7-2)、题目集5(7-4)两种日期类聚合设计的优劣比较
1、题目集4(7-2)
这道题并没有拿到满分,其中部分算法有问题,只能过一些特定的点,根据上图中各类的最大圈复杂度,圈复杂度相加还是挺大的,最主要的问题是程序并不完美,前n天和后n天计算出的结果都不对,而且运行的时间特别长,运行非常慢。
2、题目集5(7-4)
相较于题目集4的7-2,算法改进后,圈复杂度也减小了许多,程序也能运行,计算出正确的结果,而且运行时间也明显缩短了,唯一美中不足的是示例点计算有一点偏差,目前也没找到程序的问题,但别的测试点都能过。
比较:题目集4中的聚合属于类间的多次聚合,在Day类中用Month定义month,在Month类中用Year定义year等,这样在DateUtil中调用时要跨过多层调用,增加了出错率,而且效率也变低了。
而题目集5中的聚合则是一次聚合,所有需要使用的类都在DateUtil中一次聚合,这样调用也方便避免跨多个类调用,调用方便,运行速度也加快了。
②题目集4(7-3)、题目集6(7-5、7-6)三种渐进式图形继承设计的思路与技术运用(封装、继承、多态、接口等)
1、题目集4(7-3)
该题进行了继承和封装,但是继承的并不是同一个类,因为图形间的联系不一样,Rectangle和Circle是基础图形,继承Shape,求面积以及输出“Constructing Shape”,Ball和Box与Circle和Rectangle相关,所以继承,而且输出的Constructing能明显体现继承间的关系。
该题难度不大,思路清晰,按题目要求进行封装和继承即可。而且程序的复杂度不算特别大,除了类间的继承,主要就是主函数的switch-case语句,基本没其他无用的东西。
2、题目集6(7-5)
该题运用了抽象类、继承、封装和ArrayList接口的知识点,以抽象类Shape为父类,其他子类均继承于它,在子类中重写父类的方法,主要运用ArrayList接口添加新创建的对象,并用冒泡排序法进行排序。
该题根据类图提示,定义抽象的Shape类为父类,在思路上也没有难点,主要要注意ArrayList接口的使用,用arrayList.add(circle);增加元素,用arrayList.get(i).getArea()获取元素等,还要注意有接口情况下的冒泡排序的使用方法。该题的主函数的圈复杂度也不是很大,程序简单明了,根据输入的数字创建相应个数的对象,通过for循环实现,用if 语句判断输入合法性情况。
3、题目集6(7-6)
该题主要涉及使用接口和类实现多态性,定义一个GetArea的接口,各个图形类来实现这个接口,并将各个变量进行封装,在各个图形类中写getArea的方法,运用时直接用接口定义一个新的对象。
根据下图,圈复杂度很小,该程序按照类图提示来书写也特别简单,只要了解接口和类的联系使用,让定义的图形类实现这一接口。
③对三次题目集中用到的正则表达式技术的分析总结
1、题目集3(7-1)水文数据校检及处理
对数据的合法性检验,各数据之间采用“|”符号进行分隔
对输入的日期合法性进行检验,如闰年二月,每月的最大天数等,其中年份取值范围为[1,9999],“月”与“日”为一位数时之前不加“0”,日期与时间之间有一个空格,“时”与“分”之间采用冒号分隔(英文半角),“时”为一位数时之前不加“0”,“分”始终保持两位,且始终为“00”。注意:“时”数必须是24小时进制中的偶数值。
对输入的水位、流量进行检验,均为实型数,取值范围为[1,1000), 小数点后保留1-3位小数或无小数(也无小数点)
对开度进行检验,实型数,取值范围为[1,10),必须保留2位小数,两个开度之间用“/”分隔
2、题目集5(7-4)统计Java程序中关键词的出现次数
匹配一种注释符(*/ /*),匹配到即将里面的内容去掉,因为注释部分不算关键字
将所有的符号换成空格,然后按照空格来切割
3、题目集6(7-1)QQ号校验
对QQ号进行校验,要求必须是 5-15 位;0 不能开头;必须都是数字,1-9开头,中间4位到14位可以是0-9
4、题目集6(7-3)验证码校验
对验证码进行检验,由四位数字或者字母(包含大小写)组成的字符串
5、题目集6(7-4)学号校验
对20级学生学号进行检验,学号共八位,要求:
- 1、2位:入学年份后两位,例如20年
- 3、4位:学院代码,软件学院代码为20
- 5位:方向代码,例如1为软件工程,7为物联网
- 6位:班级序号
- 7、8位:学号(序号)
前四位为2020(软件学院),1方向1-7或者61或者7方向1-3或者8方向1-2(班级),学号1-9的为01-09,然后1或2或3再加任意一个数字(11-39),再然后还有一个40。
④题目集5(7-4)中Java集合框架应用的分析总结
1、定义存放关键字的数组
2、定义Map接口,并遍历存放关键字的keys数组,将每个关键字的个数赋为0
3、定义判断是否输入和是否有关键字出现的变量
4、对注释符号进行处理,先拆分字符串,再将拆分的的字符串拼接起来
5、将所有的符号换成空格并切割成单个的字符
6、对切割好的字符进行遍历,并改变出现的次数
7、对输出情况进行分类谈论,分为无有效代码,都是注释或空、有代码但无关键字和有代码且有关键字,第三种情况中,将map转换为map.Entry<String,Integer>元素的列表,同时通过重写CompareTo方法,来使用sort对键进行排序
8、最后,按照排好的顺序打印出关键字及其出现的次数
踩坑心得
1、题目集4(7-2)
算法有误,年份在变化,但day.month.year.isLeapYear()一直没变,导致误差很大。
算法有误,年份在变化,但day.month.year.isLeapYear()一直没变,导致闰年情况没有处理。
2、题目集4(7-3)
判断条件出错,之前写的是||,方法中没有参数,传入的参数没有作用
圆的面积的计算公式出错,立方体的表面积计算公式出错,而且计算结果没有保留两位小数
传入的参数没有传入成功,没有起作用
新定义的类的位置不对
输出面积时少了:输出格式不对。
计算方法有误
输出格式有误
3、题目集5(7-4)
刚开始没有正确处理符号,符号的正则表达式有误,而且切割空格的正则写成(" "),导致切割的不太好
不会使用Map的接口改变内部类的值,通过询问别人才学会的
最开始把continue写成break,导致循环一次就没有了,后面的关键字不能输出
4、题目集5(7-5)
有一个点运行超时,之前定义的n是int 型,得改成Long型才可以,因为int 型的数值过小
无论输入什么值,程序都不会执行上面的语句(判断是闰年,sum = sum + 366),判断闰年的语句有误
5、题目集6(7-1)
定义正则表达式时没有写开始符号和结束符号,导致只能匹配相同的[1-9][0-9]{4,14}才算验证成功
6、题目集6(7-5)
排序直接用了Arrays.sort()的排序方法,导致里面为空,所以换了冒泡排序的方法,但冒泡排序的使用方法和平时的不太一样,而且用Shape定义的对象不小心写成一样的。
改进建议
1、 题目集4(7-2)
算法需要改进,得到前n天,得到后n天和两日期天数之差的算法都有问题,改进具体如下(改进的方法在题目集5的7-5已经实现,所以代码是另一种聚合方式的代码,但方法和算法是一样的:
public void getNextDays(int n) { int y = this.day.month.year.getValue(); int m = this.day.month.getValue(); int d = this.day.getValue(); for(int i= 0; i < n; i++) { d ++; if(d > day.getMon_maxnum()[m] && day.month.year.isLeapYear() == false) { d = 1; m++; } else if(d > day.getMon_maxnum()[m] + 1 && day.month.year.isLeapYear() == true && m == 2) { d = 1; m++; } else if(d > day.getMon_maxnum()[m] && day.getMonth().getYear().isLeapYear() == true && m != 2) { d = 1; m++; } if(m > 12) { m = 1; y++; } } showDate(d,m,y); } public void getpreviousDays(int n) { int y = day.month.year.getValue(); int m = day.month.getValue(); int d = day.getValue(); for(int i = 0; i < n;i++) { d--; if(d < 1 && day.month.year.isLeapYear() == false) { m--; d = day.getMon_maxnum()[m]; } else if(d < 1 && day.month.year.isLeapYear() == true && m == 2) { m--; d = day.getMon_maxnum()[m] + 1; } else if(d < 1 && day.month.year.isLeapYear() == true && m != 2) { m--; d = day.getMon_maxnum()[m]; } if(m < 1) { m = 12; y--; } } showDate(d,m,y); } public void getDaysofDates(DateUtil date1,DateUtil date2) { int y = date1.day.month.year.getValue(); int m = date1.day.month.getValue(); int d = date1.day.getValue(); int y1 = date2.day.month.year.getValue(); int m1 = date2.day.month.getValue(); int d1 = date2.day.getValue(); int n = Math.abs(numOfDays(y,m,d) - numOfDays(y1,m1,d1)); System.out.println(n); } //求出year-month-day到0001-1-1的距离天数,返回整型数; public static int numOfDays(int year,int month,int day) { int year1 = year - 1; int month1 = month - 1; int day1 = day; int year2 = 1; int flag = 0; while(year2 < month) { if((year2 % 4 == 0 && year2 % 100 != 0) || year2 % 400 == 0) flag++; year2++; } int sum = 0; int month2[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; for(int i = 0;i < month;i++) { sum = sum + month2[i]; } if(month > 2) { if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { sum = sum + 1; } } int days = 365 * (year1 - flag) + 366 * flag + sum + day1; return days; } } public void showDate(int d,int m,int y) { System.out.println(y + "-" + m + "-" + d); }
int[] mon_maxnum = {0,31,28,31,30,31,30,31,31,30,31,30,31}; int[] mon_maxnum1 = {0,31,29,31,30,31,30,31,31,30,31,30,31}; public DateUtil getNextNDays(Long n) { int y = this.year.getValue(); int m = this.month.getValue(); int d = this.day.getValue(); DateUtil date = new DateUtil(y,m,d); for(int i= 0; i < n; i++) { date.day.value ++; if(date.day.value > mon_maxnum[date.month.value] && date.year.isLeapYear() == false) { date.day.value = 1; date.month.value ++; if(date.month.value > 12) { date.month.value = 1; date.year.value ++; } } else if(date.day.value > mon_maxnum1[date.month.value] && date.year.isLeapYear() == true) { date.day.value = 1; date.month.value ++; if(date.month.value > 12) { date.month.value = 1; date.year.value ++; } } } return new DateUtil(date.year.value,date.month.value,date.day.value); } public DateUtil getPreviousNDay(Long n) { int y = year.getValue(); int m = month.getValue(); int d = day.getValue(); DateUtil date = new DateUtil(y,m,d); for(int i = 0; i < n;i++) { date.day.value--; while(date.day.value < 1) { date.month.value--; if (date.month.value < 1) { date.month.value = 12; date.year.value --; } if(date.day.value < 1 && date.year.isLeapYear() == false) { date.day.value = mon_maxnum[date.month.value]; } else if(date.day.value < 1 && date.year.isLeapYear() == true) { date.day.value = mon_maxnum1[date.month.value]; } } } return new DateUtil(date.year.value,date.month.value,date.day.value); } public String showDate() { return year.getValue() + "-" + month.getValue() + "-" + day.getValue(); } public int getDaysofDates(DateUtil date) { return this.getDate() - date.getDate(); } public int getDate() { int y = year.getValue(); int m = month.getValue(); int d = day.getValue(); DateUtil date = new DateUtil(y,m,d); int sum = date.day.value - 1; for(int i = 1; i < date.month.value; i++) { if(date.year.isLeapYear() == true) { sum = sum + mon_maxnum1[i]; } if(date.year.isLeapYear() == false) { sum = sum + mon_maxnum[i]; } } while(date.year.value > 1) { if(date.year.isLeapYear() == true) { sum = sum + 366; //System.out.println("sa"); } else sum = sum + 365; date.year.value --; } return sum; } }
2、题目集4(7-1)
水文数据的题目计算那部分还需改进,之前压根就没写,就直接放弃了,因为没有看懂题目的计算方法。
总结
这一阶段的练习让我强化了对正则表达式的掌握和运用,还了解了两种不同的聚合方式,感受两种聚合方式的区别,这有助于我的理解和以后对聚合的运用,除此之外,还学会了不同的继承设计,如:结合封装性、多态性、接口等,区别了他们之间的差异。
尤其是接口,这是第一次接触,通过这一阶段的练习,我了解并学习了三种不同的接口(Set、Map、List接口),了解了他们的使用用法,如何增删,如何获取元素等,还了解了他们之间的区别,List和Set是存储单列数据的集合,Map是存储键值对这样的双列数据的集合;List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的。但这只是了解,具体还需要花时间去掌握,这样以后使用接口时可以根据题目要求进行分析取舍。
作业方面,我认为现在这个难度和题量就差不多可以,既不是那种随随便便就可以写出来的题目,也不是那种绞尽脑汁也写不出来的题目,而且在题目中涉及到新的知识点,这样也方便我们自己去学习掌握,但对一些稍微较难的题目,还是希望老师可以讲解一下,或者以后出很难的题目时可以适当提示。课下发布的网课,让我们自学,我觉得这个方式很好,但有时候看了网课也是云里雾里,有的没太看懂,有的看了感觉自己懂了,但又感觉没掌握,所以课下的网课还是需要一些习题巩固,希望老师能适当指导。