对Java课程PTA4-6题目集的反思与总结

发布时间 2023-04-28 20:15:53作者: 检

 

前言:

  三次题目集一共涵盖了以下知识点:面向对象编程的封装性,List-Arrays方法的使用,强制类型转换的方法,字符串的处理,字符串截断方法split的使用,对象数组的建立以及使用,Java源码自带的多种日期类方法的使用,各种正则表达式及其运用,运用聚合的方法自行写日期类,综合运用现学的所有知识写在一个程序里面。这三次题目集的题量不如前几次多,但是每个题目的难度都比前几次更大,尤其是第六次作业,难度比前几次都大,需要综合运用很多所学的知识,这几次的得分都非常不理想,Java学习进入爬坡阶段。

设计与分析:

集训4

7-1菜单计价程序-3

import java.util.Scanner;
public class Main{    
public static void main(String[] args){

Scanner input
= new Scanner(System.in);int i = 0; while(true) { String dishname = input.nextLine(); if(dishname.equals("end")) break; String[] a = dishname.split(" "); if(a.length<=3){ if(!a[1].equals("delete")) menu.addDish(a[0],Integer.parseInt(a[1]),i); else order.delARecordByOrderNum(Integer.parseInt(a[0])); } else { if(a[0].equals("table")) { if(Integer.parseInt(a[1])<=50&&Integer.parseInt(a[1])>=1) { String[] b1 = a[2].split("\\/"); String[] b2 = a[3].split("\\/"); if(Integer.parseInt(b1[0])==2022) { m[2] += 1; if(Integer.parseInt(b1[1])<=12&&Integer.parseInt(b1[1])>=1&&Integer.parseInt(b1[2])>=1&&Integer.parseInt(b1[2])<=m[Integer.parseInt(b1[1])]) ; } if(Integer.parseInt(b1[0])==2023&&Integer.parseInt(b1[1])<=12&&Integer.parseInt(b1[1])>=1&&Integer.parseInt(b1[2])>=1&&Integer.parseInt(b1[2])<=m[Integer.parseInt(b1[1])]) ; else System.out.println("not a valid time period"); } else System.out.println(a[1] + " table num out of range"); } else if(a.length==4) { order.addARecord(Integer.parseInt(a[0]),a[1],Integer.parseInt(a[2]),Integer.parseInt(a[3]),i); System.out.println(order.records[i]); } else System.out.println("Wrong Format"); //} //i++; }

  由于开始写这道题的时间太晚了,所以没有在规定的时间内上交程序,导致编写终止,但是,从这道题我也学习到了很多内容。首先就是对输入字符串内容的处理方法问题,本来对于这种大量字符串输入的处理,想用正则表达式处理,因为正则表达式本身就是由大量if,else语句构成的,利用正则表达式可以简略很多,但是,由于本人对于正则表达式的学习还不够,不够了解如何正确使用,而且正则表达式也不够熟练,所以不能够完美的运用,所以,选择了使用字符串处理方法中的split方法用空格将字符串分割开,然后进行后续的处理。由于把输入的所有东西都放入了字符串里面,所以在后续与数字比较的时候,需要强制类型转换为int型,所以程序非常繁琐。但是,通过这道题,我了解了面向对象程序设计的意义,利用对象数组可以使问题简化很多。

7-3去掉重复的数据

import java.util.Scanner;
import java.util.ArrayList;
public class Main{
    public static void main(String[] args){
        Scanner aaa = new Scanner(System.in);
        int n = aaa.nextInt();
        ArrayList<Integer> list = new ArrayList<>();
        int value,i=0;
        do{
            value = aaa.nextInt();
            if(!list.contains(value))
                list.add(value);
            i++;
        }while(i<n);
        for(i=0;i<list.size();i++){
        System.out.print(list.get(i));
            if(i!=list.size()-1)
                System.out.print(" ");
            else
                System.out.print("\n");
    }
}
}

  本题看上去是和前几次当中的某一道题一模一样,但是我却没有拿到满分,原因是,代码不够优化,运行时间过长。通过本题我了解到,Arraylist方法对一组数据的查找是非常迅速的,但是,对于数组中个别元素的增删改相对于查找就显得尤其慢,所以为了提高程序的运行速度,我将每一个输入的数据都与已有的数据进行匹配,如果在已有数据当中没有输入的那个数据,则将其存入数组,最后输出。虽然这样的操作提高了程序的运行速度但是终究是太慢了,因为每次查找虽然很快,但是还是相对来说费时间,而且打印输出的时候用了for循环,循环里面还有两个判断,所以运行速度非常慢。本来第一遍是用字符串写的,但是字符串也需要用到很多个循环,所以就换了数组。之所以会出戏i按这种情况,我认为是因为算法不够简洁明了或者有更快的工具我没有接触到,我会继续再接再厉,争取解决这类问题。

7-4单词统计与排序

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String s1 = input.nextLine();
        String[] arr2 = s1.split("\\,|\\ |\\.");//截断字符串
        int i,k,j,a,b;
        String t = "";
        
        for(i=0;i<arr2.length;i++)
            for(j=i+1;j<arr2.length;j++){
                if(arr2[i].length()<arr2[j].length()){
                    t = arr2[i];
                    arr2[i] = arr2[j];
                    arr2[j] = t;
                }
                //相等字符串之间逐个查询
                else if(arr2[i].length()==arr2[j].length()){
                    for(k=0;k<arr2[i].length();k++){
                        a = arr2[i].charAt(k);
                        b = arr2[j].charAt(k);
                        if(a>=97)
                            a -= 32;
                        if(b>=97)
                            b -= 32;
                    if(a>b){
                         t = arr2[i];
                        arr2[i] = arr2[j];
                        arr2[j] = t;
                        break;
                }
            }
                }      
        }
        for(k=0;k<arr2.length;k++){
            
         
            System.out.println(arr2[k]);
            
        }
        
    }
}

  首先,将输入的字符存放在s1当中,然后用split方法将s1以逗号,空格,句号为分隔将字符串分为多个字符串存放在字符串数组arr[]当中,然后利用双循环将字符串数组按照字符串长度降序排序,再将长度相等的字符串之间,逐个字母比较,最后输出全部字符串。本题的算法较为简单,但是一分都没有拿到,原因就是,用split方法截断字符串的时候,总会有多余的空字符,由于时间有限,没能想到合适的方法来解决这个问题,所以这题就寄咯,哎!

7-7判断两个日期的先后,计算间隔天数,周数

import java.util.Scanner;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String s1 = input.nextLine();
        String s2 = input.nextLine();
        String[] arr1 = s1.split("-");
        String[] arr2 = s2.split("-");
        int a1 = Integer.parseInt(arr1[0]);
        int a2 = Integer.parseInt(arr1[1]);
        int a3 = Integer.parseInt(arr1[2]);
        int b1 = Integer.parseInt(arr2[0]);
        int b2 = Integer.parseInt(arr2[1]);
        int b3 = Integer.parseInt(arr2[2]);
        LocalDate date1 = LocalDate.of(a1,a2,a3);
        LocalDate date2 = LocalDate.of(b1,b2,b3);
        if(date1.equals(date2))
            System.out.print("两个日期相等");
            else{
            
        if(date1.isBefore(date2))
            System.out.println("第一个日期比第二个日期更早");
        else
            System.out.println("第一个日期比第二个日期更晚");
        long day = date1.until(date2,ChronoUnit.DAYS);
        long week = date1.until(date2,ChronoUnit.WEEKS);
        System.out.println("两个日期间隔" + Math.abs(day) +"天");
        System.out.print("两个日期间隔" + Math.abs(week) +"周");   
        }
    }
}

  首先,将输入的字符串分别放在s1,s2当中,由于日期的数字之间是用“-”链接的,所以有需要用到split方法将其分隔开存放在arr[]数组里面,由于该类型为字符串类型,所以要将他们全部强制类型转换为int型,以便后续的处理。本题技巧性不强,但是需要查阅大量的资料以学习日期类的各种方法,增强了自己的自学能力。同时,通过本题,我了解到了input.next()与input.nextLine()的区别。input.next()的读入是,只要遇到了空格或者换行符就停止读入,而input.nextLine()遇到空格不会停止,遇到换行符才会停止读入。

集训5

7-4

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String s = input.next();
        String ss = "";
        String regstr = "\\D";
        Pattern compile = Pattern.compile(regstr);
        Matcher matcher = compile.matcher(s);
        while(matcher.find()){
            ss += matcher.group(0);
        }
        if(s.length()!=8||ss.length()!=0)
            System.out.print("错误");
        else{
            char[] a = s.toCharArray();
            int[] b ={2,0,2,0};
            int flag = 1;
            for(int i=0;i<4;i++)
                if(a[i]!=b[i]){
                    flag = 0;
                    break;
                }
            switch(a[4]){
                case 1:{
                    if(a[5]>8||a[5]<1){
                        flag = 0;
                        break;
                    }
                    else if(a[6]*10+a[7]>40||a[6]*10+a[7]<1){
                        flag = 0;
                        break;
                    }
                        }
                case 7:{
                    if(a[5]<1||a[5]>3){
                        flag = 0;
                        break;
                    }
                    else if(a[6]*10+a[7]>40||a[6]*10+a[7]<1){
                        flag = 0;
                        break;
                    }
                }
                case 8:{
                    if(a[5]<1||a[5]>2){
                        flag = 0;
                        break;
                    }
                    else if(a[6]*10+a[7]>40||a[6]*10+a[7]<1){
                        flag = 0;
                        break;
                    }
                }
                default:{
                    flag = 0;
                    break;
                        }
            }
            if(flag==0)
                System.out.print("错误");
            else
                System.out.print("正确");
        }
    }
}

  本次集训加入了正则的训练,正则表达式是一个很好的工具,它可以处理大量的字符串输入,只要按照合理的方式写正则表达式,就能够很快的处理好一大串的字符串,同时,正则表达式也是一个很好的按一定规则将字符串分成字符数组进行处理的工具,比split好用多了,因为split只能处理一行的字符串而正则能处理大量的字符串。本题的算法较为简单,首先判断输入的字符串长度是否为8,若不是8直接输出“错误”结束整个程序,若输入的字符串长度为8,则进入else语句的switch语句进行判断,最终得出结论。本次集训的正则表达式练习题比较简单,终于让我有了一些自信。

7-5日期问题面向对象设计(聚合一)

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.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.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.print(fromDate.getDaysofDates(toDate));
            } else {
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        else{
            System.out.println("Wrong Format");
            System.exit(0);
        }        
    }
}
class DateUtil{
    Day day;
    int[] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public DateUtil(){
        
    }
    public DateUtil(int y,int m,int d){
        this.day = new Day(y,m,d);
    }
    public Day getDay(){
        return day;
    }
    public void setDay(Day d){
        this.day = d;
    }
    public boolean checkInputValidity(){//判断日期合法
        if(this.getDay().getMonth().getYear().Validate()&&this.getDay().getMonth().Validate()&&this.getDay().Validate())
            return true;
        else
            return false;
    }
    public boolean compareDates(DateUtil date){//this日期在前为true
        if((this.getDay().getMonth().getYear().getvalue()<date.getDay().getMonth().getYear().getvalue())||
           (this.getDay().getMonth().getYear().getvalue()==date.getDay().getMonth().getYear().getvalue()&&this.getDay().getMonth().getvalue()<date.getDay().getMonth().getvalue())||
           (this.getDay().getMonth().getYear().getvalue()==date.getDay().getMonth().getYear().getvalue()&&this.getDay().getMonth().getvalue()==date.getDay().getMonth().getvalue()&&this.getDay().getvalue()<date.getDay().getvalue()))
            return true;
        else
            return false;
    }
    public boolean equalTwoDates(DateUtil date){//判断两日期是否相等
        if(this.getDay().getMonth().getYear().getvalue()==date.getDay().getMonth().getYear().getvalue()&&this.getDay().getMonth().getvalue()==date.getDay().getMonth().getvalue()&&this.getDay().getvalue()==date.getDay().getvalue())
            return true;
        else
            return false;
    }
    public String showDate(){//输出
        return getDay().getMonth().getYear().getvalue()+"-"+getDay().getMonth().getvalue()+"-"+getDay().getvalue();
    }
    public DateUtil getNextNDays(int n){
        int sum1=0,sum2=0,sum=0,i,j,y,t,d;
        if(this.getDay().getMonth().getYear().isLeapYear())//闰年二月加一
            m[2] += 1;
        for(i=this.getDay().getMonth().getvalue()+1;i<=12;i++){//除去本月剩下的距离下一年的天数sum1
            sum1 += m[i];
        }
        sum2=m[this.getDay().getMonth().getvalue()]-this.getDay().getvalue();//本月剩余天数
        sum = sum1+sum2;//距离下一年的总天数
        if(sum>n){//下n天的本年
            y=this.getDay().getMonth().getYear().getvalue();
            if(sum2>=n){//下n天在本月
                t=this.getDay().getMonth().getvalue();
                d=n+this.getDay().getvalue();
            }
            else{//下n天在本年不在本月
                n -= sum2;
                this.getDay().getMonth().monthIncrement();//月份加一
                t=this.getDay().getMonth().getvalue();
                i=t;
                d=n;
                while(n-m[i]>0&&i<=12){
                    n=n-m[i];
                    this.getDay().getMonth().monthIncrement();//月份加一
                    i++;
                }
                t=this.getDay().getMonth().getvalue();
                d=n;
            }
        }
        else{//下n天不在本年
            n -= sum;
            this.getDay().getMonth().getYear().yearIncrement();//年份加一
            int c=365;
            y=this.getDay().getMonth().getYear().getvalue();
            if(new Year(y).isLeapYear()){
                c++;
            }
            while(n-c>0){
                n -= c;
                y++;
                c=365;
                if(new Year(y).isLeapYear())//因为年份一直在变化所以每一年都要判断
                    c++;
            }
            i=1;
            while(n-m[i]>0&&i<=12){
                n=n-m[i];
                i++;
            }
            t=i;
            d=n;
        }
        return new DateUtil(y,t,d);
    }
    public DateUtil getPreviousNDays(int n){
        int sum1=0,sum2=0,sum=0,i,j,y,t,d;
        if(this.getDay().getMonth().getYear().isLeapYear())
            m[2] += 1;
        for(i=1;i<this.getDay().getMonth().getvalue();i++){//除去本月过去的天数和
            sum1 += m[i];
        }
        sum = this.getDay().getvalue();//本月过去的天数和
        sum2= sum1+sum;//本年过去的天数和
        if (sum2>n){//前n天在本年
            y=this.getDay().getMonth().getYear().getvalue();
            if(sum>n){//前n天在本月
                t=this.getDay().getMonth().getvalue();
                d=sum-n;
            }
            else{//前n天不在本月
                n=n-sum;
                this.getDay().getMonth().monthReduction();//月份减一
                t = this.getDay().getMonth().getvalue();
                i=t;
                while(n-m[i]>0&&i>=0){//
                    n=n-m[i];
                    this.getDay().getMonth().monthReduction();//月份减一
                    i--;
                }
                t = this.getDay().getMonth().getvalue();
                d=m[i]-n;
                if(new Year(y).isLeapYear()&&t==2){
                    d++;
                }
            }
        }
        else{//前n天不在本年
            n=n-sum2;
            this.getDay().getMonth().getYear().yearReduction();//年份减一
            y=this.getDay().getMonth().getYear().getvalue();
            int f=365;
            if(new Year(y).isLeapYear()){//闰年天数加一
                f++;
            }
            while(n-f>0){//减去整年的,确保最后的n小于365
                n=n-f;
                y--;
                f=365;
                if(new Year(y).isLeapYear())
                    f++;
            }
            i=12;
            while(n-m[i]>0&&i>=0){//
                n=n-m[i];
                i--;
            }
            t=i;
            d=m[i]-n;//
            if(new Year(f).isLeapYear()&&t==2){//如果是二月,还有一天被减去了,所以要加一
                d++;
            }
        }
        return new DateUtil(y,t,d);
    
    }
    public int getDaysofDates(DateUtil date){
       DateUtil b1=this;
        DateUtil b2=date;
        if(this.equalTwoDates(date)){
            return 0;
        }
        else if(!this.compareDates(date)){
            b1=date;
            b2=this;
        }
        int i,j,s=0;
        for(i=b1.getDay().getMonth().getYear().getvalue()+1;i<b2.getDay().getMonth().getYear().getvalue();i++){
            s += 365;
            if(new Year(i).isLeapYear())
                s++;
        }
        if(b1.getDay().getMonth().getYear().getvalue()==b2.getDay().getMonth().getYear().getvalue()&&b1.getDay().getMonth().getvalue()==b2.getDay().getMonth().getvalue()){//年份相同,月份相同,日不同
            s=b2.getDay().getvalue()-b1.getDay().getvalue();
        }
        else if(b1.getDay().getMonth().getYear().getvalue()==b2.getDay().getMonth().getYear().getvalue()&&b1.getDay().getMonth().getvalue()!=b2.getDay().getMonth().getvalue()){//年份相同,月份不同
            if(b1.getDay().getMonth().getYear().isLeapYear())
                m[2] += 1;
            s += m[b1.getDay().getMonth().getvalue()]-b1.getDay().getvalue();
            s += b2.getDay().getvalue();
                s+=m[i];
        }
        else if(b1.getDay().getMonth().getYear().getvalue()!=b2.getDay().getMonth().getYear().getvalue()){
            s=s+m[b1.getDay().getMonth().getvalue()]-b1.getDay().getvalue();
            s=s+b2.getDay().getvalue();
            for(j=b1.getDay().getMonth().getvalue()+1;j<=12;j++)
                s=s+m[j];
            for(j=b2.getDay().getMonth().getvalue()-1;j>0;j--)
                s=s+m[j];
            if(b1.getDay().getMonth().getYear().isLeapYear()&&b1.getDay().getMonth().getvalue()<=2)
                s++;
            if(b2.getDay().getMonth().getYear().isLeapYear()&&b2.getDay().getMonth().getvalue()>2)
                s++;
        }
        return s;
        }
    }
class Day{
    int value;
    Month month;
    int[] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public Day(){
        
    }
    public Day(int y,int m,int d){
        this.month = new Month(y,m);
        this.value = d;
    }
    public int getvalue(){
        return this.value;
    }
    public void setvalue(int value){
        this.value = value;
    }
    public Month getMonth(){
        return month;
    }
    public void setMonth(Month value){
        this.month = value;
    }
    public void reseMin(){
        this.value = 1;
    }
    public void reseMax(){
        this.value = m[this.getMonth().getvalue()];
    }
    public boolean Validate(){
        if(this.getMonth().getYear().isLeapYear())
            m[2] += 1;
        if(value<=m[this.getMonth().getvalue()]&&value>=1)
            return true;
        else
            return false;
    }
    public void dayIncrement(){
            value += 1;
    }
    public void dayReduction(){
            value -= 1;
    }
}
class Month{
    int value;
    Year year;
    public Month(){
        
    }
    public Month(int y,int m){
        this.year = new Year(y);
        this.value = m;
    }
    public int getvalue(){
        return value;
    }
    public void setvalue(int m){
        this.value = m;
    }
    public Year getYear(){
        return year;
    }
    public void setYear(Year year){
        this.year = year;
    }
    public void reseMin(){
        value = 1;
    }
    public void reseMax(){
        value = 12;
    }
    public boolean Validate(){
        if(value>=1&&value<=12)
            return true;
        else
            return false;
    }
    public void monthIncrement(){
        value += 1;
    }
    public void monthReduction(){
        value -= 1;
    }
}
class Year{
    int value;
    public Year(){
        
    }
    public Year(int y){
        this.value = y;
    }
    public int getvalue(){
        return value;
    }
    public void setvalue(int y){
        this.value = y;
    }
    public boolean isLeapYear(){
        if(value%400==0||(value%4==0&&value%100!=0))
            return true;
        else
            return false;
    }
    public boolean Validate(){
        if(value<=2050&&value>=1900)
            return true;
        else
            return false;
    }
    public void yearIncrement(){
        value += 1;
    }
    public void yearReduction(){
        value -= 1;
    }
}

  

 

  熟悉的日期类设计又来了,这题的分值是50分,只拿了46分呜呜呜。原因是前n天又有两个测试点没过,有逻辑错误,但是没能改出来。不过通过这个题目,不仅增强了我的代码能力(写了313行),更重要的是这题让我更加了解类间关系是怎么一回事。本题将Day类作为DateUtil类的一个属性,将Month类作为Day类的一个属性,将Year类作为Month类的一个属性,环环相扣,所以,在引用各个类里面的属性的时候就要环环相扣,增加了代码的复杂度,如下图:

 由于在Day,Month,Year类当中都写了判断日期是否合法的方法,所以使DateUtil类中判断日期是否合法的算法变得更简单。计算nextdays和previousdays时的算法类似,首先判断输入的n是否大于本年剩余天数和本年已经过去天数,若小于,则年份不变,若大于,则逐年减去整年的天数,在用剩下的天数去计算。而计算两日期相间隔天数时,先判断哪个日期在前,然后大的日期向小的日期靠拢,逐次计算。

  本题的设计思维非常巧妙,糅合了很多知识点,尤其在聚合方面的训练,使我对聚合更加了解。但是,日期类的算法比较复杂,对我这种逻辑思维不是很强的人来说实属不易。而且这种聚合方法让各个类之间环环相扣,耦合性太强了。Java是开源的,有时间应该多看看源码,通过源码学习各种算法应该是一个比较有趣的学习方法。

7-6 日期问题面向对象设计(聚合二)

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(year + "-" + month + "-" + day + " next " + m + " days is:");
            System.out.print(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(
                    year + "-" + month + "-" + day + " previous " + n + " days is:");
            System.out.print(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.print("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{
    Year year;
    Month month;
    Day day;
    int[] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public DateUtil(){
        
    }
    public DateUtil(int y,int m,int d){
        this.year = new Year(y);
        this.month = new Month(m);
        this.day = new Day(d);
    }
    public Year getYear(){
        return this.year;
    }
    public void setYear(Year year){
        this.year = year;
    }
    public Month getMonth(){
        return this.month;
    }
    public void setMonth(Month month){
        this.month = month;
    }
    public Day getDay(){
        return this.day;
    }
    public void setDay(Day day){
        this.day = day;
    }
    public boolean checkInputValidity(){
        if(this.year.isLeapYear())
            m[2] += 1;
        if(this.year.validate()&&this.month.validate()&&this.day.value>=1&&this.day.value<=m[this.month.value])
            return true;
        else
            return false;
    }
    public DateUtil getNextNDays(int n){
        int sum1=0,sum2=0,sum=0,i,j,y,t,d;
        if(this.year.isLeapYear())
            m[2] += 1;
        for(i=this.month.getvalue()+1;i<=12;i++){
            sum1 += m[i];
        }
        sum = sum1+m[this.month.getvalue()]-this.day.getvalue();
        if(sum>n){
            y=this.year.getvalue();
            sum2=m[this.month.getvalue()]-this.getDay().getvalue();//本月剩余天数
            if(sum2>=n){
                t=this.month.getvalue();
                d=n+this.day.getvalue();
            }
            else{
                n -= sum2;
                t=this.month.getvalue()+1;
                i=t;
                while(n-m[i]>0&&i<=12){
                    n=n-m[i];
                    t++;
                    i++;
                }
                d=n;
            }
        }
        else{
            n -= sum;
            y=this.year.getvalue()+1;
            int c=365;
            if(new Year(y).isLeapYear()){
                c++;
            }
            while(n-c>0){
                n -= c;
                y++;
                c=365;
                if(new Year(y).isLeapYear())
                    c++;
            }
            i=1;
            while(n-m[i]>0&&i<=12){
                n=n-m[i];
                i++;
            }
            t=i;
            d=n;
        }
        return new DateUtil(y,t,d);
    }
    public DateUtil getPreviousNDays(int n){
        int sum1=0,sum2=0,sum=0,i,j,y,t,d;
        if(this.year.isLeapYear())
            m[2] += 1;
        for(i=month.getvalue()+1;i<=12;i++){
            sum1 += m[i];
        }
        sum += m[this.month.getvalue()]-this.day.getvalue();
        sum2=365-sum;
        if(this.year.isLeapYear()){
           sum2++;
        }
        if (sum2>n){
            y=this.year.getvalue();
            int e=this.day.getvalue();
            if(e>n){
                t=this.month.getvalue();
                d=e-n;
            }
            else{
                n=n-e;
                t=this.month.getvalue()-1;
                i=t;
                while(n-m[i]>0&&i>=0){//
                    n=n-m[i];
                    t--;
                    i--;
                }
                d=m[i]-n;
                if(new Year(y).isLeapYear()&&t==2){
                    d++;
                }
            }
        }
        else{
            n=n-sum2;
            y=this.year.getvalue()-1;
            int f=365;
            if(new Year(y).isLeapYear()){
                f++;
            }
            while(n-f>0){
                n=n-f;
                y--;
                f=365;
                if(new Year(y).isLeapYear())
                    f++;
            }
            i=12;
            while(n-m[i]>0&&i>=0){//
                n=n-m[i];
                i--;
            }
            t=i;
            d=m[i]-n;//
            if(new Year(f).isLeapYear()&&t==2){
                d++;
            }
        }
        return new DateUtil(y,t,d);
    }
    public boolean compareDates(DateUtil date){
        if((this.year.value<date.year.value)||(this.year.value==date.year.value&&this.month.value<date.month.value)||(this.year.value==date.year.value&&this.month.value==date.month.value&&this.day.value<date.day.value))
            return true;
        else
            return false;
    }
    public boolean equaltwoDates(DateUtil date){
        if(this.year.value==date.year.value&&this.month.value==date.month.value&&this.day.value==date.day.value)
            return true;
        else
            return false;
    }
    public int getDaysofDates(DateUtil date){
        if(equaltwoDates(date))
            return 0;
        else
            return 1;
        
    }
    public String showDate(){
        return this.year.value+"-"+this.month.value+"-"+this.day.value;
    }
}
class Year{
    int value;
    public Year(){
        
    }
    public Year(int value){
        this.value = value;
    }
    public int getvalue(){
        return this.value;
    }
    public void setValue(int value){
        this.value = value;
    }
    public boolean isLeapYear(){
        if(value%400==0||(value%100!=0&&value%4==0))
            return true;
        else
            return false;
    }
    public boolean validate(){
        if(value<=2020&&value>=1820)
            return true;
        else
            return false;
    }
    public void yearIncrement(){
        value += 1;
    }
    public void yearReduction(){
        value -= 1;
    }
}
class Month{
    int value;
    public Month(){
        
    }
    public Month(int value){
        this.value = value;
    }
    public int getvalue(){
        return this.value;
    }
    public void setValue(int value){
        this.value = value;
    }
    public void reseMin(){
        value = 1;
    }
    public void reseMax(){
        value = 12;
    }
    public boolean validate(){
        if(value<=12&&value>=1)
            return true;
        else
            return false;
    }
     public void monthIncrement(){
        if(value<12)
            value += 1;
        else
            reseMin();
    }
    public void monthReduction(){
        if(value>1)
            value -= 1;
        else
            reseMax();
    }
}
class Day{
    int value;
    public Day(){
        
    }
    public Day(int value){
        this.value = value;
    }
    public int getvalue(){
        return this.value;
    }
    public void setValue(int value){
        this.value = value;
    }
    public void dayIncrement(){
        value += 1;
    }
    public void dayReduction(){
        value -= 1;
    }
}

  

 

  熟悉的日期类,熟悉的算法,但是又与前面不同,本题虽然也是用的聚合,方式却与上一题大不相同。本题将Day,Month,Year类都作为DateUtil类的属性,而Day,Monrh,Year类的内容与前面7-5的区别不大,只有一个区别,就是,在Day,Month,Year类当中,没有了日期合法性的判断方法,而把所有日期合法判断都放到了DateUtil类里面,使得那里的判断复杂了一些。但是在别的地方应用Day,Month,Year类里面的属性就变得更加简单,而且对于Day,Month,Year类里面的属性的getter和setter更加简单,如图:

 

 这种聚合方法,优点就是使编程更加简单,类与类之间的耦合性更小了,更加适合面向对象编程的原则。

集训6

7-1菜单计价程序

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        Dish dish = new Dish();
        Menu menu = new Menu();
        Order order = new Order();
        Record record = new Record();
        int[] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        int i = 0;
       while(true) {
            String dishname = input.nextLine();
            if(dishname.equals("end"))
                break;
            String[] a = dishname.split(" ");
            if(a.length<=3){
                if(!a[1].equals("delete"))
                    menu.addDish(a[0],Integer.parseInt(a[1]),i);
                else
                    order.delARecordByOrderNum(Integer.parseInt(a[0]));
            }
            else {
                if(a[0].equals("table")) {
                    if(Integer.parseInt(a[1])<=50&&Integer.parseInt(a[1])>=1) {
                        String[] b1 = a[2].split("\\/");
                        String[] b2 = a[3].split("\\/");
                        if(Integer.parseInt(b1[0])==2022) {
                            m[2] += 1;
                            if(Integer.parseInt(b1[1])<=12&&Integer.parseInt(b1[1])>=1&&Integer.parseInt(b1[2])>=1&&Integer.parseInt(b1[2])<=m[Integer.parseInt(b1[1])])
                                 ;
                        }    
                        if(Integer.parseInt(b1[0])==2023&&Integer.parseInt(b1[1])<=12&&Integer.parseInt(b1[1])>=1&&Integer.parseInt(b1[2])>=1&&Integer.parseInt(b1[2])<=m[Integer.parseInt(b1[1])])
                            ;
                        else
                            System.out.println("not a valid time period");
                    }
                    else
                        System.out.println(a[1] + " table num out of range");
                }
                else if(a.length==4) {
                    order.addARecord(Integer.parseInt(a[0]),a[1],Integer.parseInt(a[2]),Integer.parseInt(a[3]),i);
                    System.out.println(order.records[i]);
                }
                else
                    System.out.println("Wrong Format");
            }
            i++;    
        }
       System.out.println(order.getTotalPrice());
    }
}
class Dish{
    String name;//菜品名称
    double unit_price;//单价
    
    public Dish() {
        
    }
    public int getPrice(int portion){
        int price = 0;//价格
        switch(portion){
            case 1: price = (int)unit_price;break;//小份
            case 2: price = (int)(unit_price*1.5 + 0.5);break;//中份
            case 3: price = (int)(unit_price*2 + 0.5);break;//大份
        }
        return price;
    }
    
}
class Menu{
    Dish[] dish;//菜品数组
    
    public Menu() {
        
    }
    
    public Dish searthDish(String dishName){//查找菜品信息
        int i=0;
        for(i=0;dish[i]!=null;i++) {
            if(dish[i].name==dishName)
                return dish[i];
        }
        return dish[i];
    }
    
    public Dish addDish(String dishName,int util_price,int i){//添加菜品
        dish[i].name = dishName;
        dish[i].unit_price = util_price;
        return dish[i];
    }
}
class Record{
    int orderNum;//序号
    Dish d;//菜品
    int portion;//份额
    
    public Record() {
        
    }
    
    public int getPrice(){
        return d.getPrice(portion);
    }
    
}
class Order {
    Record[] records;//保存订单上每一道的记录
    
    public Order() {
        
    }
    
    public int getTotalPrice(){//计算订单的总价
        int i;
        int sumprice = 0;
        for(i=0;records[i]!=null;i++) {
            sumprice += records[i].getPrice();
        }
        return sumprice;
    }
    
    public Record addARecord(int orderNum,String dishName,int portion,int num,int i){//添加一条菜品信息到订单中
        records[i].orderNum = orderNum;
        records[i].d.name = dishName;
        records[i].d.unit_price = num;
        records[i].portion = portion;
        return records[i];
    }
    
    public void delARecordByOrderNum(int orderNum){//根据序号删除一条记录
        records[orderNum] = null;
    }
    
    public Record findRecordByNum(int orderNum){//根据序号查找一条记录
        return records[orderNum];
    }
}

  本题的算法也有些复杂,而且,由于有一大串字符串输入,尚未找到合适的方法去处理。原本看到一大串字符串输入,首先想到的是使用正则表达式去将字符串分段,但是,目前所学正则表达式只能按照数字,符号,字符进行分类截取,而输入的字符串又包含了所有的信息,所以处理起来非常麻烦。本次使用的依然是split方法,将字符串按照空格截取,然后再进行逐个字符串的处理。由于算法复杂,条件太多了,导致只能写出一些非常简单的判断,还是能力不够。本次题目又运用了对象数组的方法,由于实验一已经有所练习,所以这方面没有什么太大的问题。这次也是采用的聚合,聚合真是一个很方便的方法。

踩坑心得:

一:没有弄清楚input.next()和input.nextLine()的区别,导致在ecilipse上面测试了半个多小时还是没有能够解决这个问题,最后发现是读取有问题,查阅了一些资料才发现问题出在这里。如图:

 二:用split方法截取字符串的时候经常产生多余的空格,所以,在长文本截取的时候就会暴露很多弊端,如图:

 查阅资料后,有如下解决办法:

改进建议:

   对于菜单计价程序,其实算法可能并不是那么难,只是对于一大段字符串的处理不够合理,让算法变得复杂了起来,所以,我应该改进一下字符串处理。

总结:

  这三次集训的题目,给我印象最深刻的就是菜单计价程序,因为不花时间是真的什么都写不出来,而且就算花了时间,知识储备不够还是徒劳。不过通过这几次集训,学到了很多面向对象程序设计的方法,对类间关系有了更深刻的理解,尤其是耦合性,通过两次日期类的作业,比较了两次聚合方法的优缺点。更重要的是,给我提了一个醒,Java的学习需要花费大量的时间,想要提高自己的编码能力,多写程序是避免不了的。还有各种对字符串的处理方法,这块是真的没有知识储备,所以后续要加强这方面的练习。对于复杂的程序,很难想清楚合适的算法,这不仅是逻辑能力的问题,而且是看待问题,并且将其抽象成模型的问题,在这方面目前还没有想到合适的解决办法。

  对老师的建议:希望老师能够在PTA截止时间过后,将较难的题目的答案发出来。老师说编程没有标准答案,但是我想说,目的并不是得到某个题目的标准答案,而是,在比较难的题目依靠自己目前的能力无法很好地解决的时候,有一个正确的程序可以作为参考,并且从中获得解决问题的方法和思路,这样,做这个题目才有了意义。否则,如果有些题目不会的话,就只是给自己增添焦虑,对能力的提升没有那么大的作用,在练习中学习,不失为一种很好的学习方式。感谢!