一、前言

这三次PTA作业涉及的知识量非常广,这几次作业主要是进行了一些Java基础语法和面向对象思想的锻炼。

1、第一次作业

每一道作业都使用了Scanner类进行键盘输入,而其中第二题和第六题使用了Java中数组的知识,剩下的几道题都是使用if-else或switch语法进行解答,一共八道题,题目是数量虽然较多,但是题目都比较简单,只有最后一道题稍微难一点。

2、第二次作业

第二次作业一共五题,第一题IP地址转换中主要使用了String类中的charAt()方法和substring()方法以及Integer类中的parseInt()方法,第二题则使用了Arrays类中的sort()方法和增强for循环,后三道题都是有关日期的题目使用数组和if-else便可以解答,这几道题目都比较简单。

3、第三次作业

第三次作业一共三题,题目不算多,这几题主要是为了锻炼我们的面向对象的思想。每一题都要采用类进行解答,在这几题get和set方法对进行问题的解答有着很大的帮助,前两题比较简单,而最后一道题较难,在最后一道题中使用到了正则表达式、String类中的repalce()方法、split()方法、charAt()方法、indexOf()方法和substring()方法, StringBuilder类中的append()方法和toString()方法,BigInteger类中的multiply()方法、subtract()方法、equals()方法和compareTo()方法,这道题运用的知识非常多导致其相较于前两题较难。

二、设计与分析

1、判断三角形类型

输入三角形三条边,判断该三角形为什么类型的三角形。

输入格式:

在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。

输出格式:

(1)如果输入数据非法,则输出“Wrong Format”; (2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”; (3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”; (3)如果输入数据合法且能够成等腰直角三角形,则输出“Isosceles right-angled triangle”; (5)如果输入数据合法且能够成等腰三角形,则输出“Isosceles triangle”; (6)如果输入数据合法且能够成直角三角形,则输出“Right-angled triangle”; (7)如果输入数据合法且能够成一般三角形,则输出“General triangle”。

我写的代码如下:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        double num1=sc.nextDouble();
        double num2=sc.nextDouble();
        double num3=sc.nextDouble();
        double temp;
        if(num1>num2){
            temp=num1;num1=num2;num2=temp;
        }
        if(num1>num3){
            temp=num1;num1=num3;num3=temp;
        }
        if(num2>num3){
            temp=num2;num2=num3;num3=temp;
        }
        if(num1>=1&&num1<=200&&num2>=1&&num2<=200&&num3>=1&&num3<=200){
            if(num1+num2>num3){
                if(num1==num2&&num2==num3)
                    System.out.println("Equilateral triangle");
                else if(num1*num1+num2*num2-num3*num3<0.000001&&num1==num2)
                    System.out.println("Isosceles right-angled triangle");
                else if((num1==num2&&num1!=num3)||(num1==num3&&num1!=num2)||(num2==num3&&num2!=num1))
                    System.out.println("Isosceles triangle");
                else if(num1*num1+num2*num2-num3*num3<0.000001)
                    System.out.println("Right-angled triangle");
                else
                    System.out.println("General triangle");
            }
            else
                System.out.println("Not a triangle");
        }
        else
            System.out.println("Wrong Format");
    }
}

 


我这道题的Source Monitor:

 

从Source Monitor可以看出我这份代码是不够合格的,Avg Complexity、AvgDepth等都是超标了的,其原因是我使用了很多if-else语句、&&和||运算符,这道题目的思路会很清晰,就是不断判断不同三角形的各自的特点,这只能使用if-else进行解答。

2、求下一天

输入格式:

在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。

输出格式:

  1. 当输入数据非法及输入日期不存在时,输出“Wrong Format”;
  2. 当输入日期合法,输出下一天,格式如下:Next date is:年-月-日   

  

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int a=sc.nextInt();
        int b=sc.nextInt();
        int c=sc.nextInt();
         nextDate(a,b,c);
    }
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 !=0 )||year % 400 == 0;
    }
    public static boolean checkInputValidity(int year,int month,int day) {
        boolean checkInputValidity;
        int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
        if(!isLeapYear(year))
            a[2] = 28;
        checkInputValidity = (year>=1820&&year<=2020&&month>0&&month<=12&&day<=a[month]&&day>0);
        return checkInputValidity;
    }
    public static void nextDate(int year,int month,int day) {
        int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
        int d,m;
        if(!isLeapYear(year))
            a[2] = 28;
        if(checkInputValidity(year,month,day)) {
            if(month==12) {
                if(day==a[month]) {
                    year = year+1;
                    m = 1;
                    d=1;
                }
                else{
                    m=month;
                    d =day +1;
                }
            }
            else {
                if(day==a[month]) {
                    m = month + 1;
                    d = 1;
                }
                else{
                    m=month;
                    d = day+1;
                }
            }
            System.out.println("Next date is:"+year+"-"+m+"-"+d);
        }
        else
            System.out.println("Wrong Format");
    }
}

 

我这道题的Source Monitor:

 


从图中可以看出这份代码的各项指标基本处于绿色内,证明这份代码还是比较良好的,这道题思路同样比较清晰,进行输入后求下一天,需要注意的是要注意月末时月份会加一而日会变成一,其中当月份为12时,年份也同样会进行加一操作。


3、求前N天

输入格式:

在一行中输入年月日的值以及n的值,可以用一个或多个空格或回车分隔。

输出格式:

 

  1. 当输入的年、月、日以及n的值非法时,输出“Wrong Format”;
  2. 当输入数据合法时,输出“n days ago is:年-月-日”
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int a=sc.nextInt();
        int b=sc.nextInt();
        int c=sc.nextInt();
        int d=sc.nextInt();
        if (!checkInputValidity(a,b,c,d))
        {
            System.out.println("Wrong Format");
            return;
        }
         nextDate(a,b,c,d);
    }
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 !=0 )||year % 400 == 0;
    }
    public static boolean checkInputValidity(int year,int month,int day,int n) {
        boolean checkInputValidity;
        int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
        if(!isLeapYear(year))
            a[2] = 28;
        checkInputValidity = (year>=1820&&year<=2020&&month>0&&month<=12&&day<=a[month]&&day>0&&n<=10&&n>=-10);
        return checkInputValidity;
    }

    public static void nextDate(int year,int month,int day,int n) {
        int[] a={0,31,28,31,30,31,30,31,31,30,31,30,31};
        if (isLeapYear(year))
            a[2]=29;
        day-=n;
        if (n>0){
            while (day<=0){
                month--;
                if (month==0){
                    month+=12;
                    year--;
                }
                day+=a[month];
            }
        }else if (n<0){
            while (day>a[month]) {
                day-=a[month];
                month++;
                if (month==13){
                    month-=12;
                    year++;
                }
            }
        }
        System.out.printf("%d days ago is:%d-%d-%d\n",n,year,month,day);
    }
}

 

我这道题的Source Monitor:

 


 由此可以看出各项指标都处于绿色内,这说明这份代码是良好的,这一题其实是求后一天的变化题,这道题的解题思路就像上一题那样,只不过这个n可以较大且可以为负数,将其是正数还是负数分类讨论即可完成这道题目。

4、定义日期类

输入格式:

在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。

输出格式:

  • 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
  • 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
import java.util.Scanner;
public class Main {
    public static  void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Date a = new Date();
        a.setYear(sc.nextInt());
        a.setMonth(sc.nextInt());
        a.setDay(sc.nextInt());
        Date.nextDate(a.getYear(), a.getMonth(), a.getDay());
    }
}
      class Date {
        int year;
        int month;
        int day;

          public Date() {
          }

          public int getYear() {
            return year;
        }

        public void setYear(int year) {
            this.year = year;
        }

        public int getMonth() {
            return month;
        }

        public void setMonth(int month) {
            this.month = month;
        }

        public int getDay() {
            return day;
        }

        public void setDay(int day) {
            this.day = day;
        }

          public static boolean isLeapYear(int year) {
              return (year % 4 == 0 && year % 100 !=0 )||year % 400 == 0;
          }
          public static boolean checkInputValidity(int year,int month,int day) {
              boolean checkInputValidity;
              int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
              if(!isLeapYear(year))
                  a[2] = 28;
              checkInputValidity = (year>=1900&&year<=2000&&month>0&&month<=12&&day<=a[month]&&day>0);
              return checkInputValidity;
          }
          public static void nextDate(int year,int month,int day) {
              int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
              int d,m;
              if(!isLeapYear(year))
                  a[2] = 28;
              if(checkInputValidity(year,month,day)) {
                  if(month==12) {
                      if(day==a[month]) {
                          year = year+1;
                          m = 1;
                          d=1;
                      }
                      else{
                          m=month;
                          d =day +1;
                      }
                  }
                  else {
                      if(day==a[month]) {
                          m = month + 1;
                          d = 1;
                      }
                      else{
                          m=month;
                          d = day+1;
                      }
                  }
                  System.out.println("Next day is:"+year+"-"+m+"-"+d);
              }
              else
                  System.out.println("Date Format is Wrong");
          }
      }

 

我这道题的Source Monitor:

 


这道题除了Max Complexity较高之外,其余的指标都处于绿色范围内,这道题其实就是用类的思想来实现第二次作业的第三题,使用get和set方法可以更加方便地进行数据的存取。


5、一元多项式求导(类设计)

输入格式:

在一行内输入一个待计算导函数的表达式,以回车符结束。

输出格式:

  1. 如果输入表达式不符合上述表达式基本规则,则输出“Wrong Format”。
  2. 如果输入合法,则在一行内正常输出该表达式的导函数,注意以下几点: 结果不需要排序,也不需要化简;
  • 当某一项为“0”时,则该项不需要显示,但如果整个导函数结果为“0”时,则显示为“0”;
  • 当输出结果第一项系数符号为“+”时,不输出“+”;
  • 当指数符号为“+”时,不输出“+”;
  • 当指数值为“0”时,则不需要输出“x^0”,只需要输出其系数即可。
import java.math.BigInteger;
import java.util.Scanner;
public class Main  {
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        String temp=in.nextLine();
        Derivation dv=new Derivation();
        dv.setPolynthic(temp);
        dv.print(); 
    }
}
class Derivation{
    private static final String sign;
    private static final String number;
    private static final String regex;
    private static final String regex1;
    private static final String regex2;
    private static final String regex3;
    private static final String concat;
    private static final String concatend;
    private static final String specialnum;
    private static final String end;
    static {
        sign="(?:[+|-])";
        number="(?:([1-9](\\s*\\d*\\s*)*))";
        specialnum="((?:(\\s*([+|-]?[1-9]+\\s*\\d*)\\s*))*)";
        regex="(?:(([1-9](\\s*\\d*\\s*)*)\\s*\\*\\s*x\\s*\\^\\s*[+|-]?\\s*([1-9](\\s*\\d*\\s*)*)))";
        regex1="(?:(x\\s*\\^\\s*[+|-]?\\s*([1-9](\\s*\\d*\\s*)*)))";
        regex2="(?:(([1-9](\\s*\\d*\\s*)*)\\s*\\*\\s*x))";
        regex3="(?:x)";
        concat="("+regex+"|"+regex1+"|"+regex2+"|"+regex3+")";
        concatend="("+concat+"|"+number+")";
        end="(?:("+"\\s*"+sign+"?\\s*"+concatend+"(?:\\s*"+sign+"\\s*"+concatend+"\\s*)*"+"))";
    }
    private String Polynthic;
    public Derivation(){}
    public void setPolynthic(String polynthic) {
        this.Polynthic = polynthic;
    }
    private boolean isLegal() {
        String s=Polynthic;
        if(s.matches(specialnum))
            return true;
        return s.matches(end);
    }
    public void print() {
        if(isLegal()) printLegal();
        else  printNotLegal();
    }
    private void printNotLegal() {
        System.out.println("Wrong Format");
    }
    private  void printLegal() {
        String s=Polynthic;
        s=s.replace(" ","");
        char[] t=s.toCharArray();
        for(int i=0;i<s.length()-1;i++)
            if(t[i]=='^'&&t[i+1]=='-') t[i+1]='#';
        StringBuilder s1= new StringBuilder();
        for (char c : t)
            s1.append(c);
        s1 = new StringBuilder(s1.toString().replace("^+", "^"));
        s1 = new StringBuilder(s1.toString().replace("-", "+-"));
        String [] id= s1.toString().split("\\+");
        int flag=0;
        int lazy=0;
        for(String e :id) {
            e=e.replace("#","-");
            int start=e.indexOf("x");
            int mid=e.indexOf("*");
            int end=e.indexOf("^");
            if(start!=-1&&end!=-1) {
                if(mid!=-1) {
                    BigInteger pro=new BigInteger(e.substring(0,mid));
                    BigInteger pos= new BigInteger(e.substring(end+1));
                    BigInteger xishu=pro.multiply(pos);
                    BigInteger zhishu=pos.subtract(new BigInteger(1+""));
                    if(zhishu.equals(new BigInteger(0+""))) System.out.print(xishu);
                    else {
                        if(xishu.equals(new BigInteger(1+""))) System.out.print("x^"+zhishu);
                        else if(xishu.equals(new BigInteger(-1+"")))System.out.print("-x^"+zhishu);
                        else {
                            if(    xishu.compareTo(new BigInteger(0+""))>0)
                                if(flag==1) System.out.print("+");
                            System.out.print(xishu+"*x^"+zhishu);
                        }
                    }
                }
                else {
                    BigInteger pos=new BigInteger(e.substring(end+1));
                    BigInteger xishu;
                    if(e.charAt(0)=='-') {
                        xishu = pos.multiply(new BigInteger(-1 + ""));
                    }
                    else {
                        xishu = pos.multiply(new BigInteger(1 + ""));
                    }
                    BigInteger zhishu=pos.subtract(new BigInteger(1+""));
                    if(zhishu.equals(new BigInteger(0+""))) System.out.print(xishu);
                    else {
                        if(xishu.equals(new BigInteger(1+""))) System.out.print("x^"+zhishu);
                        else if(xishu.equals(new BigInteger(-1+"")))System.out.print("-x^"+zhishu);
                        else {
                            if(    xishu.compareTo(new BigInteger(0+""))>0)
                                if(flag==1) System.out.print("+");
                            System.out.print(xishu+"*x^"+zhishu);
                        }
                    }
                }
                lazy=1;
                if(flag==0) flag=1;
            else if(start!=-1) {
                if(mid!=-1) {
                    BigInteger num=new BigInteger(e.substring(0, mid));
                    System.out.print(num);
                }
                else {
                    BigInteger num;
                    if(e.charAt(0)=='x') num=new BigInteger("1");
                    else if(e.charAt(0)=='-') num=new BigInteger("-1");
                    else
                        num=new BigInteger(e.substring(0, start));
                    System.out.print(num);
                }
                lazy=1;
                if(flag==0) flag=1;
            }
            else
                System.out.print("");
        }
        if(lazy==0) System.out.println(0);
    }
}

 

我这道题的Source Monitor:

 


 从中可以看出这道题的复杂程度,这道题要使用正则表达式、BigInteger类中的一些方法、String类中的一些方法和StringBuilder类中的一些方法综合运用进行解答,我在写这题时一开始也遇到了许多问题。

三、踩坑心得

1、首先就是编程中最常见的错误了,有时在提交代码时莫名其妙会多出字符或少了字符。如图所示:

三次PTA题目集的总结_输出格式

 

 

在这次提交中就在最后一行少了一个}符号。

 

 

2、输出格式错误

 

三次PTA题目集的总结_正则表达式_02

 

在这次提交中因为一个空格导致格式错误。

 

3、在写判断三角形类型这道题时,我没有考虑到Java中没有根号,导致在判断等腰直角三角形时答案错误

 

 三次PTA题目集的总结_java_03

 

利用余弦定理判断是否为直角时需要两个边的平方和减去第三条边的平方小于0.000001即可

4、在使用类的思想时在类的前面加了public导致编译错误

三次PTA题目集的总结_输出格式_04

 

我在一开始使用类时并不知道在main类中其他的class不能用public进行修饰。

5、在写一元多项式求导这道题时,我一开始并没有使用正则表达式和BigInteger类,在中途时仔细看了word文档发现了正则表达式和大数据测试,在经过正则表达式的学习后,我利用正则表达式的匹配轻松地

解决了多项式的合格检验问题,而学习了BigInteger类后,知道了BigInteger类的底层是使用了数组来进行超大整数的表示,而且其中的multiply()方法、subtract()方法正好可以用于多项式的求导。

 

小总结:这几次作业暴露了我很多的问题,比如:粗心、知识量不足等,在编程中应当仔细,在不使用IDE时我们很难发现一些小错误,一些符号的漏写和多写。我们同样要注意输出的格式一定要按照题目来,不然就会没一个答案正确,现在我们还只是学习到了Java的一些皮毛,对Java的学习还远远不够,我希望在将来的学习中我能学习到更多的知识,同时我还应该多看、多写、多用API,对其中的常用的类和方法进行更多的学习,要更加灵活地运用这些类和方法。

 

 四、改进建议

1、在判断三角形类型这道题中,我使用了很多if-else语句导致其的圈复杂度很高,但因为这道题就是进行一个判断,我也很难降低其的圈复杂度。

2、在第二次作业的第三题中,我使用了很多if-else语句进行数据合理性判断,在提交时结果完全正确,但在下一题的使用中出现了错误,下一题的代码限制长度为3KB,我的代码过于长导致出现错误,而发现利用数组可以很好的解决这一问题。

这是我数据合理性判断的代码:

 

              if(b<1||b>12){
System.out.println("Wrong Format");
return;
}
if(c<1){
System.out.println("Wrong Format");
return;
}
if(b==1&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==2&&isLeapYear(a)&&c>29){
System.out.println("Wrong Format");
return;
}
if(b==2&& !isLeapYear(a) &&c>28){
System.out.println("Wrong Format");
return;
}
if(b==3&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==4&&c>30){
System.out.println("Wrong Format");
return;
}
if(b==5&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==6&&c>30){
System.out.println("Wrong Format");
return;
}
if(b==7&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==8&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==9&&c>30){
System.out.println("Wrong Format");
return;
}
if(b==10&&c>31){
System.out.println("Wrong Format");
return;
}
if(b==11&&c>30){
System.out.println("Wrong Format");
return;
}
if(b==12&&c>31){
System.out.println("Wrong Format");
return;
}

改进前这个代码很长,而且使用了很多if-else和&&,圈复杂度很高。
boolean checkInputValidity;
int[] a=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};
if(!isLeapYear(year))
a[2] = 28;
checkInputValidity = (year>=1820&&year<=2020&&month>0&&month<=12&&day<=a[month]&&day>0);
return checkInputValidity;
利用数组改进后只需要几行代码就能直接判断数据合理性。

 

3、在一元多项式求导这道题中,数组可以来进行字符串匹配,但这样的效率很低,而使用正则表达式则可以很好地解决这一问题,Java中int类型有效范围为-2,147,483,648至2,147,483,647,long类型范围是 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 ,而这道题测试的数据结果在long类型范围之外,导致使用long不能完全正确,使用BigInteger类则可以很好地解决这一问题,其中的很多方法也很好地解决了多项式求导的问题。

 

五、总结

在这几次作业中我学到了很多,,我了解了自己的不足,在编程中最重要的就是要仔细,我学习了正则表达式和BigInteger类这两个我之前完全不知道的知识以及通过作业进一步了解了面向对象的思想,类中的get和set方法对于数据的存取非常好用。老师在上课时讲的雨刷问题和农夫过河问题很大地提升了我对面向对象的理解,希望老师还能多多在上课时让我们进行实践。