(1)前言:
第一次作业:
知识点:主要是刚入门面向对象程序编程的一些基础性知识点,大部分类似 c语言,因此先学过c语言的情况下写这次题目还是较为简单的,有的也是细节上的问题。主要知识点有:对实际问题的合法性判断(在PTA里这个要先判断,不行要立即return,不能用if-else放到后边else里判断,不然测试点是通过不了的,其他的放到踩坑心得里说),选择语句(if-else,swtich以及嵌套使用等),控制输出的格式(String.format("%d",12345);和与c语言格式化输出大同小异的system.out.printf(""),这个主要是用于控制一些小数的精确程度),截取字符串中的一小段(substring),获取某字符在字符串中第一次出现的位置索引(indexOf),比较字符串(equals,这个与==的比较方法就完全不同,==可以用来比较基本类型的值,也可以用来比较引用类型的地址值;equals则不能用来比较基本类型的值,可以比较引用类型的地址值,相对的可以在需要的类中重写equals方法,使得可以比较对象中的特定内容,例如String类就可以比较不同类中的字符串内容了)
这次作业的题量是较小的,但是难度对于刚刚入手java刚刚好,算是非常简单的了
第二次作业:
知识点:主要是考类的使用,以及类之间的配合关系,7-4的小明走格子,考对很大数据的量的处理方法,用到了快读和快写(在应对很大的数据的时候能够很明显的加快速度)和 动态规划(类似递归),7-3题,考关于日期类和方法的使用,用到了String类中split(),Integer类中parseInt()等方法,LocalDate类中of()、isAfter()、isBefore()、until()等方法,ChronoUnit类中DAYS、WEEKS、MONTHS等单位。7-2/7-1菜单题,ArrayList,Math.round()用来计算四舍五入等
第二次作业相比第一次的作业难度就提高很多了,比如小明走格子刚开始用c语言的思维一下子写了好几层嵌套循环,结果一直在超时,题量虽少,但是难度高,光写一题的时间就能写完一次作业一了。而菜单一二是为后续更新菜单打了个基础。
第三次作业
知识点:主要考了哈希表Hashset(对加入数组列表的数据自动去重,还可以有自动排序功能),类的封装性(public private protect package),String.format("%d",12345)格式化输出,与作业二类似的关于日期类的方法的使用。菜单三多了个Table类,也需要用到时间类,再加上一个对输入格式判断的解析类(这里好像可以用正则表达式替换,让代码更简洁)
除了菜单三外,作业三整体上比作业二简单了不少,题量也适中。菜单三多了个Table类,不能在菜单二的基础上直接加上去,需要修改很多地方才能插入对Table类的编程,差不多算是重新写了一遍菜单了,测试的时候出了一点小问题就要改很多地方和花很多时间,是真的难。
(2)设计与分析:
题目集1的题目:主要考察基础知识,较为简单,便不详细分析。
较为有用是在学号识别和二进制提取,用到了字符串截取和字符串索引,在对信息处理时非常有用
.substring()和.indexOf()
题目集2的7-4:小明走格子
设计与解释:
1.使用快读快些
2.对需要判定的组数的合法性判定
3.动态规划
1 import java.io.*; 2 import java.util.Scanner; 3 4 public class Main 5 { 6 public static void main(String[] args) throws IOException 7 { 8 9 StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));//快读 10 11 int gezi[]=new int[10000]; 12 int bushu[]=new int [10000]; 13 re.nextToken(); 14 int number = (int)re.nval; 15 int i,j; 16 int max=0; 17 if(number>10000)//合法性判定 18 { 19 return; 20 } 21 22 for(i=0;i<number;i++) 23 { 24 re.nextToken(); 25 gezi[i]=(int)re.nval; 26 27 if(max<gezi[i]) 28 { 29 max=gezi[i]; 30 } 31 } 32 bushu[1]=1; 33 bushu[2]=2; 34 bushu[3]=4; 35 bushu[4]=8; 36 for(j=5;j<=max;j++) 37 { 38 bushu[j]=bushu[j-1]+bushu[j-2]+bushu[j-3]+bushu[j-4];//动态规划 39 } 40 41 for(i=0;i<number;i++) 42 { 43 System.out.println(bushu[gezi[i]]+""); 44 } 45 46 47 } 48 }
分析:这个PTA测试点里有一个非常大的测试点,导致测试点超时,为了减少用时,需要用上快读快写,不能无脑用多层嵌套循环,故要换成动态规划。这个题目是一个基础知识的大升级,在之后的编程里可以加快编译速度。
题目集3的7-2:有重复的数据
设计与解释:对删除重复的数据,可以用哈希表,也可以用嵌套循环删掉与前面相同的数据,当然用哈希表更为简洁,我这里用的是嵌套循环。

分析:即使不用哈希表也较为简单,用哈希表就非常简便了,单纯算是关于哈希表的一个练习题
题目集7-3:去掉重复的数据
设计与解释:哈希表

题目集7-4:单词统计与排序
设计与解释:1.放入哈希表去重
2.遍历哈希表区别开单词大小
3.再同等单词大小里面比较


题目集2的7-1:


设计与解释:根据需求,除了Main类外还设计4个类:Dish(菜)类:保存菜信息,Menu(菜单)类:用于保存多个菜谱信息和查找有无此菜,Record(点菜记录)类:记录一次点菜中的菜信息和份额,Order(点单)类;保存此客户的所有订单信息并算出总价。Dish类有:name姓名,unit_price单价,getPrice(int portion)计算此份额的价格。Menu类有:dishes多个菜品, searchDish(String dishName)查找菜单中有无此菜。Record类有:dish记录这个菜,portion记录这个菜的份额,getPrice()计算此菜的价格。Order类有:records保存用户的所有点菜记录,addARecord(String dishName, int portion)添加订单,getTotalPrice()计算总价格。
1 import java.util.Scanner; 2 import java.math.*; 3 class Dish {//菜品 4 String name;//菜名 5 int unit_price;//单价 6 public Dish(String name, int unit_price) { 7 this.name = name; 8 this.unit_price = unit_price; 9 } 10 public int getPrice(int portion) {//价格 11 switch (portion) { 12 case 1: 13 return unit_price; 14 case 2: 15 return (int) Math.round(unit_price * 1.5); 16 case 3: 17 return unit_price * 2; 18 default: 19 return 0; 20 } 21 } 22 } 23 class Menu {//菜单 24 Dish[] dishes;//多个菜品 25 public Menu() { 26 dishes = new Dish[4]; 27 dishes[0] = new Dish("西红柿炒蛋", 15); 28 dishes[1] = new Dish("清炒土豆丝", 12); 29 dishes[2] = new Dish("麻婆豆腐", 12); 30 dishes[3] = new Dish("油淋生菜", 9); 31 } 32 public Dish searchDish(String dishName) {//查找菜品 33 for (int i = 0; i < dishes.length; i++) { 34 if (dishes[i].name.equals(dishName)) 35 return dishes[i]; 36 } 37 return null; 38 } 39 } 40 class Record {//订单记录 41 Dish d;//菜品 42 int portion;//份额 43 public Record(Dish dish, int portion) { 44 this.d = dish; 45 this.portion = portion; 46 } 47 public int getPrice() {//价格 48 return d.getPrice(portion); 49 } 50 } 51 class Order {//总订单 52 Record[] records;//多条订单记录 53 int count;//总价格 54 public Order(int maxRecords) { 55 records = new Record[maxRecords]; 56 count = 0; 57 } 58 public Record addARecord(String dishName, int portion) {//加订单 59 Menu menu = new Menu(); 60 Dish dish = menu.searchDish(dishName); 61 if (dish == null) { 62 System.out.println(dishName + " does not exist"); 63 return null; 64 } 65 Record record = new Record(dish, portion); 66 records[count++] = record; 67 return record; 68 } 69 public int getTotalPrice() {//总价 70 int totalPrice = 0; 71 for (int i = 0; i < count; i++) { 72 totalPrice += records[i].getPrice(); 73 } 74 return totalPrice; 75 } 76 } 77 78 public class Main { 79 public static void main(String[] args) { 80 Scanner in = new Scanner(System.in); 81 Order order = new Order(100); 82 while (in.hasNextLine()) { 83 String writeOrder = in.nextLine(); 84 if (writeOrder.equals("end")) { 85 break; 86 } 87 String[] orderParts = writeOrder.split(" "); 88 String dishName = orderParts[0]; 89 int portion = Integer.parseInt(orderParts[1]); 90 Record record = order.addARecord(dishName, portion); 91 } 92 System.out.println(order.getTotalPrice()); 93 } 94 }
分析:餐馆菜单的功能,需要菜,菜单,订单记录,订单一起来完成,缺一不可。但是菜单一的题目要求相对简单,其实无需用类也可以轻易的完成需求,所以这个题目可以不用类来写,直接全部放在main方法里面,相比用类更加的简洁快速。
心得:对于简单的需求可以用c语言的思想来编写,将方法全放置在一个类中,这样简洁又快速
题目集2的7-2:


设计与解释:根据需求,与菜单一的相似但不完全相同,除了Main类外还设计4个类:Dish(菜)类:保存菜信息,Menu(菜单)类:用于保存多个菜谱信息和查找有无此菜,Record(点菜记录)类:记录一次点菜中的菜信息和份额和个数和序号,Order(点单)类;保存此客户的所有订单信息并算出总价。Dish类有:name 姓名,unit_price单价,getPrice(int portion)计算此份额的价格。Menu类有:dishes多个菜品, searchDish(String dishName)查找菜单中有无此菜,addDish(String dishName, int unit_price)添加菜到菜单。Record类有:dish记录这个菜,portion记录这个菜的份额,ordernum记录订单序号,getPrice()计算此菜的价格。Order类有:records 保存用户的所有点菜记录,addARecord(String dishName, int portion)添加订单,getTotalPrice()计算总价格,find(int ordernum) 根据序号查找一条记录,delet(int ordernum) 根据序号删除一条记录
代码较大,其他主要类已经在设计里做了解释,故这里仅放出Main方法里的代码
分析:菜单二相比菜单一,多了需要自定义加入菜单中菜品的一步,和删除订单,因此在读取输入的时候,一行内容可能是菜信息,可能是订单信息,可能是删除订单信,这个时候就要对每条读取的字符串进行解析了,此解析放在 main函数当中。比菜单一难在了对读入的解析,但是也需要在菜单一的基础上完善。
心得:基础不好,地动山摇,虽然菜单一简单,但是确实后面菜单的每一步的基础。写代码也需要循序渐进的写。
题目集3的7-1:


设计与解释:当对于菜单二,菜单三多出了Table类:区别不同桌和根据桌号的时间决定打折的大小和是否开展。和字符串解析类,table类有:桌号,本桌订单,总订单,时间,总价格,是否开张的方法,算总价的方法。字符串解析类:关于菜品,菜单,订单,桌号都有对应的方法。
代码较大,其他主要类已经在设计里做了解释,故这里仅放出Table类里的代码
分析:菜单三的难度大幅度上升,不仅要考虑多个订单,甚至多个订单间还有联系(帮他桌点单),同时还要考虑营业时间和不同时间的打折折扣,这就非常需要专门对每行的内容进行解析然后选择对应的方法解决对应问题了
心得:在测试找bug的时候可以选择注释掉后面的一些代码,一点点的测试,在大量的代码的时候更容易找到细节上的错误
(3)采坑心得:
1.对于实际问题的合法性判断:这个是我在PTA遇到的第一个百思不得其解的坑,也是偶然中发现的,先单纯说在作业上:对于有关于合法性判断的测试点,必须得将合法性判断置于代码的最上边位置,不合格则立即return退出程序或者跳过一段程序。如果将合法判断置于后面,比如if-else放在else后面,即使最后运行结果一样,但是这个测试点就是不通过。总结就是在运行某段代码前,先判断是否合法,合法则执行这段代码,不合法则不执行这段代码直接跳过。然后在代码上的理解:我认为这样的好处是可以使代码运行的更快,因为当不合格时便不会读取其他多余的代码。
2.快读快写:用快读快写时,一定要记得在方法标签后面+throws IOException,不然是运行不了的。而且在创建对象时的代码是很长的,不好记而且容易打错,所以建议把创建对象的代码复制到一个常用代码文档里,要用的时候就不用再打一遍了。
3.单词排序:先对长度排序,再在同长里面调用compareToIgnoreCase()方法。因为compareToIgnoreCase()函数在队不同长度的单词进行排序时会出现排不准的情况。还有也不能用compareTo()方法,这个方法会考虑单词的大小写,让排序不准确,题目准确写了忽略大小写,故用compareToIgnoreCase()才是最优解,可以忽略单词的大小写进行比较。
(4)主要困难以及改进建议:
1.写代码的时的细节问题和全局思想问题:写代码时总是会遗漏;{}等小细节问题,导致很多时候一运行报错了,到处找错误找不到,费了一番功夫才发现原来是某个小细节问题,同时也归咎于没有养成在报错的时候仔细看Idea给的报错可能,因为是英文所以老是懒得看。全局思想是常常遇到题目就开始写,并没有构思一下,
2.关于菜单三:由于菜单三有桌数,菜单,读入输入并按格式执行对应的程序写起来很麻烦,似乎可以用正则表达式来简化
3.数据的重复与排序:作业二7-2 7-3 7-4都是有关重复数据和排序的,当时还不知道哈希表,就只能一股脑的用循环嵌套去解决,十分的麻烦,而且经常会测试点超时。比如作业二7-2的数据就可以直接全部add入哈希表中,然后再将删除重复数据的哈希表内个数与原个数比较就行,7-3同理,最后遍历输出就行,可以极大的简化代码。
(5)总结:
知识上:学到了队类的使用,封装,String类,日期类,包装类中的一些方法,哈希表,数组列表,equals与==的不同等
思路上:学到了基本的解题步骤,需求分析,不断分解成子问题,由下向上逐步解决,阶段性调试测试,先构建出基本框架,写出基本功能,检查Bug,最后再来对整体的优化(比如让界面更简洁啊,简化一些代码啊等等)
当然还有很多没有弄明白的方面,还在学习正则表达式和javaFX动画驱动的内容,应该会对优化菜单三的解析输入内容有帮助