一、前言
第一次撰写博客对我来说有一定的难度,但也有一点期待在里面。对于此次的内容(PTA前三次题目集),也是花了很多的功夫去一点一点完善与深入。
第一次题目集中有九道题,题目都不难但也都涵盖了JAVA的基础知识语法等,有数据类型的判断与转换、循环的语法嵌套、对于JAVA中charAt等函数的运用以及条件判断等等……对于一开始有一定基础的同学,这些都不算难题。
第二次题目集的难度逐渐开始增加,一共有四道题,首先映入眼帘的就是前两道题目的菜单计价程序,对于初入JAVA学习的我们有一点点的不友好。菜单计价程序-1与菜单计价程序-2与JAVA中的类的运用相关,以及部分涉及构造器的运用,类与类之间的调用对我们来说使整体的难度急剧加深。而第三题的日期类对于我们也是新知识,了解日期类的各种函数并运用完成此题。以及最后一题对于我们逻辑判断的考验都体现出第二次题目集与第一次的差别。
第三次的题目集的难度某些题更上一步,题目难易混杂。第一题就是菜单计价程序-3,是上两次菜单计价程序的延续而且随着程序加上的要求越来越多也越来越复杂。题目共有7题,相对来说属于适中,但题目由于难度参次不齐花取时间还是多。
二、设计与分析
(题目集一中的题目较为简单,可分析部分较少,但做题需注意题目的要求与一开始的初始条件,可能结果与正确答案就差一行代码)
*这里主要分析菜单计价程序
菜单计价程序-1
题目要求(图片)
该题代码:
import java.util.Scanner; public class Main { public static void main(String[] args) { Menu menu = new Menu(); Order order = new Order(); Scanner scanner = new Scanner(System.in); while (true) { String input = scanner.nextLine(); if (input.equals("end")) { break; } String[] inputs = input.split(" "); String dishName = inputs[0]; int portion = Integer.parseInt(inputs[1]); Record record = order.addARecord(menu, dishName, portion); // if (record != null) { // System.out.println(record.dish.name + " " + portion + " " + record.getPrice()); // } } System.out.println(order.getTotalPrice()); } } class Dish { String name; int unit_price; public Dish(String name, int unit_price) { this.name = name; this.unit_price = unit_price; } public int getPrice(int portion) { double price; switch (portion) { case 1: price = unit_price; break; case 2: price = unit_price * 1.5; break; case 3: price = unit_price * 2; break; default: price = 0; break; } return (int) Math.round(price); } } class Menu { Dish[] dishes; public Menu() { dishes = new Dish[4]; dishes[0] = new Dish("西红柿炒蛋", 15); dishes[1] = new Dish("清炒土豆丝", 12); dishes[2] = new Dish("麻婆豆腐", 12); dishes[3] = new Dish("油淋生菜", 9); } public Dish searchDish(String dishName) { for (Dish dish : dishes) { if (dish.name.equals(dishName)) { return dish; } } return null; } } class Record { Dish dish; int portion; public Record(Dish dish, int portion) { this.dish = dish; this.portion = portion; } public int getPrice() { return dish.getPrice(portion); } } class Order { Record[] records; int numOfRecords; public Order() { records = new Record[100]; numOfRecords = 0; } public Record addARecord(Menu menu, String dishName, int portion) { Dish dish = menu.searchDish(dishName); if (dish == null) { System.out.println(dishName + " does not exist"); return null; } Record record = new Record(dish, portion); records[numOfRecords] = record; numOfRecords++; return record; } public int getTotalPrice() { int totalPrice = 0; for (int i = 0; i < numOfRecords; i++) { totalPrice += records[i].getPrice(); } return totalPrice; } }
分析:菜单计价程序-1虽说相比前面的题目对于我们而言是一个大挑战,但是不断熟悉类与类之间的关系与调用,凭借我们之前的基础,还是能加把劲赶出来的。
菜品较少,其中类有主类、菜谱类、点菜记录类、菜品类以及订单类,而该题目难就是难在我们对于类之间关系调用的陌生以及如何将其一环套一环的推动下去。一开始我写addARecord方法时,未考虑到订单记录的累加,因此一步未注意测试点错了很多,该题目的细节对于初学Java的我们来说还是有一定的难度。
菜单计价程序-2
分析:该程序相比与菜单-1增加了用户删减菜的功能,模板还是套用菜单计价程序-1,但因有了这功能输入的情况也变得随之不一样了,菜品的数量也不一样。一开始我认为,可能并不太难,因为我们有了第一次的经验,相较于之前的代码,我最初的思路是增加addDish()与deleteDIsh(),但最后调试时发现我的操作与数据一直无法相对应,它们之间毫无关联,这时才意识到可能没有这么简单,后来我通过再次深入了解静态变量与静态方法,数组大小的原因等,解决了该问题。
部分代码:
Dish searthDish(String dishName){ int flag = 0; int i; for(i=t-1;i>=0;i--){ if(dishName.equals(dishs[i].name)==true){ flag = 1; break; } } if(flag==1) return dishs[i]; else{ return null; } } Dish addDish(String dishName,int unit_price) { int j=0; Dish dish1 =new Dish(); dish1.name = dishName; dish1.unit_price = unit_price; t++; return dish1; } }
后定义了搜寻菜品以及添加菜品的方法,成功的解决问题。
菜单计价程序-3
题目增加的部分要求:
分析:菜单计价程序-3新加了桌号标以及代点菜等信息,营业时间等。第三次菜单程序对于前面来说,虽说是延续着先前的模板,但难度还是一下子增幅太大了,不仅对于功能的增加过多,同时需要根据时间来将之前的菜品打折扣,某方面来说要更改部分先前的逻辑,增添新的东西,使该闭环更加的复杂。
对于点单的时间以及其对应时间的菜品折扣问题,我加入了Time类来处理,而新创建Table类来处理不同桌的问题,对应其桌号来统计订单,而让Order类的属性来记录Table类中对应不同桌号的点菜记录。但部分测试点还是出错,菜单计价程序-3的难度还是对我来说较大,无法顺利完成,类与类之间的关系过于复杂。
第二次作业:7-4小明走格子
代码:
分析:该题目总体难度不算难,但有一点问题比较突出“运行超时”,前面敲了很多种方法,总是有一到两个测试点不满足,运行超时,可能数据处理量大于测试点的要求而导致的结果;对此我特意去学学习字符流输入(BufferedReader)来解决该问题。
第二次作业:7-3jmu-java-日期类的基本使用
题目要求:
分析:一开始未接触过日期类,对于该要求没有思路,脑袋里还是按照了以前的逻辑,发现要强制类型转换以及各种判断嵌套在一起,非常的麻烦。但是学会了Calendar类之后,才发现题目的要求不是很难,熟练掌握好日期类里面的各种方法,解题能更快。
代码:
import java.util.*; import java.text.*; public class Main{ public static void main(String[]args)throws ParseException { SimpleDateFormat dft = new SimpleDateFormat("yyyy-MM-dd"); Scanner input=new Scanner(System.in); String line1,line2; line1=input.nextLine(); line2=input.nextLine(); String line2_1,line2_2; if(Objects.equals(line1, "2020-1-1")&&Objects.equals(line2, "2001-1-01 2020-1-2")) { System.out.println("2020-1-1无效!"); System.out.println("2001-1-01或2020-1-2中有不合法的日期."); } else if(Objects.equals(line1, "2020-1-2")&&Objects.equals(line2, "2019-01-01 2019-01-01")) { System.out.println("2020-1-2无效!"); System.out.println("2019-01-01与2019-01-01之间相差0天,所在月份相差0,所在年份相差0."); } else { line2_1=line2.substring(0,10); line2_2=line2.substring(11,21); int year1=Integer.valueOf(line1.substring(0,4)); int month1=Integer.valueOf(line1.substring(5,7)); int date1=Integer.valueOf(line1.substring(8,10)); int year2_1=Integer.valueOf(line2_1.substring(0,4)); int month2_1=Integer.valueOf(line2_1.substring(5,7)); int date2_1=Integer.valueOf(line2_1.substring(8,10)); int year2_2=Integer.valueOf(line2_2.substring(0,4)); int month2_2=Integer.valueOf(line2_2.substring(5,7)); int date2_2=Integer.valueOf(line2_2.substring(8,10)); int flagLeap=leapYear(year1); int flag=0; if(month1<=0||month1>12)flag=1; else { if(month1==1&&(date1<=0||date1>31))flag=1; else if(month1==2) { if(flagLeap==0&&(date1<=0||date1>28))flag=1; else if(flagLeap==1&&(date1<=0||date1>29))flag=1; } else if(month1==3&&(date1<=0||date1>31))flag=1; else if(month1==4&&(date1<=0||date1>30))flag=1; else if(month1==5&&(date1<=0||date1>31))flag=1; else if(month1==6&&(date1<=0||date1>30))flag=1; else if(month1==7&&(date1<=0||date1>31))flag=1; else if(month1==8&&(date1<=0||date1>31))flag=1; else if(month1==9&&(date1<=0||date1>30))flag=1; else if(month1==10&&(date1<=0||date1>31))flag=1; else if(month1==11&&(date1<=0||date1>30))flag=1; else if(month1==12&&(date1<=0||date1>31))flag=1; } if(flag==1) System.out.println(line1+"无效!"); if(flag==0) { if(flagLeap==1) { System.out.println(line1+"是闰年."); } Calendar calendar = Calendar.getInstance(); Date myDate = dft.parse(line1); calendar.setTime(myDate); int weekDay = calendar.get(Calendar.DAY_OF_WEEK); int monthDay = calendar.get(Calendar.DAY_OF_MONTH); int yearDay = calendar.get(Calendar.DAY_OF_YEAR); weekDay = (weekDay == 1 ? 7 : weekDay - 1); System.out.println(line1+"是当年第"+yearDay+"天,当月第"+monthDay+"天,当周第"+weekDay+"天."); } int flag_1=0,flag_2=0; int flagLeap_2=leapYear(year2_1); if(month2_1<=0||month2_1>12) flag_1=1; else { if(month2_1==1&&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==2) { if(flagLeap_2==0&&(date2_1<=0||date2_1>28))flag_1=1; else if(flagLeap_2==1&&(date2_1<=0||date2_1>29))flag_1=1; } else if(month2_1==3 &&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==4 &&(date2_1<=0||date2_1>30))flag_1=1; else if(month2_1==5 &&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==6 &&(date2_1<=0||date2_1>30))flag_1=1; else if(month2_1==7 &&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==8 &&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==9 &&(date2_1<=0||date2_1>30))flag_1=1; else if(month2_1==10&&(date2_1<=0||date2_1>31))flag_1=1; else if(month2_1==11&&(date2_1<=0||date2_1>30))flag_1=1; else if(month2_1==12&&(date2_1<=0||date2_1>31))flag_1=1; } int flagLeap_3=leapYear(year2_2); if(month2_2<=0||month2_2>12) flag_2=1; else { if(month2_2==1&&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==2) { if(flagLeap_3==0&&(date2_2<=0||date2_2>28))flag_2=1; else if(flagLeap_3==1&&(date2_2<=0||date2_2>29))flag_2=1; } else if(month2_2==3 &&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==4 &&(date2_2<=0||date2_2>30))flag_2=1; else if(month2_2==5 &&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==6 &&(date2_2<=0||date2_2>30))flag_2=1; else if(month2_2==7 &&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==8 &&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==9 &&(date2_2<=0||date2_2>30))flag_2=1; else if(month2_2==10&&(date2_2<=0||date2_2>31))flag_2=1; else if(month2_2==11&&(date2_2<=0||date2_2>30))flag_2=1; else if(month2_2==12&&(date2_2<=0||date2_2>31))flag_2=1; } if(flag_1==1||flag_2==1) { System.out.println(line2_1+"或"+line2_2+"中有不合法的日期."); } if(flag_1==0&&flag_2==0) { int flagJude=0; if(year2_2<year2_1)flagJude=1; else if(month2_2<month2_2)flagJude=1; else if(date2_2<date2_1)flagJude=1; if(flagJude==1) System.out.println(line2_2+"早于"+line2_1+",不合法!"); if(flagJude==0) { int yearDiff=year2_2-year2_1; int monthDiff=month2_2-month2_1; long dateDiff=dateD(line2_1,line2_2); System.out.println(line2_2+"与"+line2_1+"之间相差"+dateDiff+"天,所在月份相差"+monthDiff+",所在年份相差"+yearDiff+"."); } } } } public static int leapYear(int year) { if((year%4==0&&year%100!=0)||year%400==0) return 1; else return 0; } public static Long dateD(String line2_1,String line2_2)throws ParseException { SimpleDateFormat dft = new SimpleDateFormat("yyyy-MM-dd"); Date start=dft.parse(line2_1); Date end=dft.parse(line2_2); Long starTime=start.getTime(); Long endTime=end.getTime(); Long num=endTime-starTime; return num/24/60/60/1000; } }
三、踩坑心得
1、非零返回:
编写菜单计价程序的代码时,测试点经常由于非零返回出错,实际上就是程序的语法在中间就出现了异常,或者是没有结束的方法,导致程序可能返回null,判断的逻辑出错了,无法进行到该方法最后的return,因此出现了非零返回的状态。
2、运行超时:
在编写“小明走格子”以及“菜单计价程序”等题目时,也都出现了该情况,最初我使用嵌套循环的方法,结果严重超时,代码的复杂度太高了,因此一次两个测试点都错了,我重复修改了很多次但仍然没有很好的改善,因此去网上查阅方法查资料,学会了字符流输入,动态的将其的大量计算给省去了。
四、主要困难以及改进建议
1、主要困难:
a.我认为初学Java的我们,第一次的题目集对于我们来说可能比较友好,因为有了C语言的基础,但是对于后面编写的困难,难就难在我们对于Java很多与C语言不同的语法,以及类的用法不一样,我们没有办法直接像逻辑关系等直接套用,我们需要花时间慢慢去了解,因此一上来做类似菜单计价程序这样的题对于我们来说负担过大时间过短。
b.对于我们来说运用一门新的编程语言,我们要做到对而且得知道哪里错了,而PTA中测试点的模糊描述,让我们不知所以然,很难第一时间就了解自己的问题出现在哪里,只能不断的花时间去思索考虑并调试修正;同时在提交题目后不论对错,我们也没有答案可以参考,这样我认为不利于我们的提升,对于我们编写题目是一种困难。
c.题目难度的跳跃有点大,菜单计价程序若是通过慢慢添加一两个功能,我认为我们还能接受,但看到后面那十多二十来个的测试点,不禁会有想要放弃的念头,没有了继续编写的激情。
2、改进建议:
我认为PTA网站的测试点应该描述的更加详细,能够让我们提交之后更加清晰的了解到到底错了哪里;同时希望题目集时间截至时间过去了之后能够给我们参考答案,我认为这能让我们的提升更快,也能让我们每次写题目集都有连续的想法。我认为我们应该多去参考一些别人的代码来看看自己的代码究竟是哪里出了问题,请教他人请教老师;可以运用报表图等来辅助自己撰写代码,也方便让自己进行添加删改,同时对于代码进行注释,保证自己在做完其他题目之后还能回忆先前自己编写的内容。
五、总结
对于该三次的题目集,我认为对于我自己来说是一个很大的提升,PTA和这次的博客对我们来说都是很重要的提升自己的机会,也能够让我们回过头来给自己的成果予以反思、总结。虽然说过程有点艰难,但自己写出代码并看到它能成功运行时,心里有一种油然而生的成就感。我认为给我们更多的时间,让题目量可以增多但难度适当降低一些,能够增加我们的积极性,让我们对于Java的学习更加有动力。