OOP课程题目集第一次总结

前言

本次总结针对于pta上第一阶段的三次题目集。

第一次题目集主要训练Java的基础语法,如if语句、for、while循环语句以及一些常见的字符串处理,题量较多,但大多简单;

第二次题目集主要训练逻辑思维,对七种基本数据类型有正确的了解和使用,进行类、构造方法等的使用, 题量一般,比较简单;

第三次作业主要训练类、构造方法等的使用,在主函数中实例化类并正确地调用相应的方法和属性解决问题,题量少,难度一般;

本次总结将对部分难题和所遇见的问题进行一次分析和总结。

总结来自:南昌航空大学-22201335

设计与分析

下面对三次题目集的部分题目进行设计与分析。

1-7 有重复的数据:

题面较少,先列出主要任务。

  • 读入数据,检查是否有重复的数据;

观察题目,数据数量是10的五次方所以最多写一重循环,可以使用Arrays.sort()方法使数据更好处理,这样计算是否有相同元素,只需要比较排序后该元素前后是否相等就可以了。

完整代码如下

import java.util.Scanner;
public class Main{
    public static void main(String []args){
        Scanner scan = new Scanner(System.in);
        int x = scan.nextInt();
        int[] c = new int[x];
        boolean t = true;
        for(int i = 0;i<x;i++){
        c[i] = scan.nextInt();
        }
        Arrays.sort(c);
        for(int i = 1;i<x;i++){
            if(c[i-1]==c[i]){
                t = false;
            }
        }
         if(t==true){
             System.out.print("NO");
        }else{
             System.out.print("YES");
        }
    }
}

 其实这样写运行时间很极限( ´◔︎ ‸◔︎`)。

相关复杂度解析

可以看出这个程序的平均复杂度还是高了以及少了足够的注释,需要一点小改进。

1-10 GPS数据处理:

先读题并简单分析,列出任务:

  • 找出$GPRMC语句,未找到则找下一条语句,数据以“END”结尾;
  • 计算校验和,找出其中校验正确;
  • 字段2的状态为 'A';
  • 计算出时间,换算成北京时间;
  • 一次数据中会包含多条$GPRMC语句,以最后一条语句得到的北京时间作为结果输出;

对其任务分别写出解决方案,大致思路如下:

1.用while循环解决数据是否结尾,用str存放语句。

String str = scan.nextLine();
while(!str.equals("END")){

2.将split方法将语句切割,用if找出$GPRMC语句。

String[] s = str.split(",");
if(!s[0].equals(right))
{
    str=in.nextLine();
    continue;
}

3. 用for循环和charAt方法算出异或的校验值。

int i = 2;
int result;
char ch;
ch=str.charAt(1);
for(result=str.charAt(1);ch!='*';ch=str.charAt(i))
{
    ch=str.charAt(i);
    result^=(int)ch;
    i++;
}
result%=65536;

4.比较校验值是否相等和字段二状态是否正确,若都为真则将存有该语句时间的字符串存入now中,以便后续打印。

char state = s[2].charAt(0);//定位状态
num=num.toLowerCase();
if(num.equals(Integer.toHexString(result))&&state=='A') {
    now = s[1];
}

5.最后用substring分割字符串来输出时间。

String hh=now.substring(0, 2);
String mm =now.substring(2, 4);
String ss =now.substring(4, 6);
int hour = Integer.parseInt(hh);
hour=(hour+8)%24;
if(hour<10) {
    System.out.print(0);//补0
}
System.out.println(hour+":"+mm+":"+ss);

最后对程序进行细节补充得:

完整代码如下

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        String str = scan.nextLine();
        String right ="$GPRMC";
        String now = null;
        while(!str.equals("END")) {
            String[] s = str.split(",");
            if(!s[0].equals(right))
            {
                str=scan.nextLine();
                continue;
            }
            int i = 2;
            int result;
            char ch;
            ch=str.charAt(1);
            for(result=str.charAt(1);ch!='*';ch=str.charAt(i))
            {
                ch=str.charAt(i);
                result^=(int)ch;
                i++;
            }
            result%=65536;
            String num = str.substring(i+1, i+3);
            char state = s[2].charAt(0);//定位状态
            num=num.toLowerCase();
            if(num.equals(Integer.toHexString(result))&&state=='A') {
                now = s[1];
            }
            str=scan.nextLine();
        }
        if(now==null){
            System.exit(0);
        }
        String hh=now.substring(0, 2);
        String mm =now.substring(2, 4);
        String ss =now.substring(4, 6);
        int hour = Integer.parseInt(hh);
        hour=(hour+8)%24;
        if(hour<10) {
            System.out.print(0);//补0
        }
        System.out.println(hour+":"+mm+":"+ss);
    }
}

相关复杂度分析:

缺点:该代码的平均复杂度高以及少了足够的注释,同时没写方法,都写在了主函数里,不易维护和复用以及分支嵌套的层数有点多。

3-3 定义日期类

 

先读题并简单分析,列出任务:

  • 定义一个Date类;
  • 在Date类中写好相应的属性和get,set方法和构造方法;
  • 对数据进行合理判断和接受;
  • 数据非法及输入日期不存在时,输出“Date Format is Wrong”;
  • 输入日期合法时,输出下一天;

对其任务逐个实现,大致思路如下:

先对类进行设计再写主函数,

类的一些主要方法,如下:

1.对润年进行判断,返回boolean值

public boolean isLeapYear(int year){
    if( (year%4 == 0 && year%100 != 0) || year%400==0 ) {
        this.mon_maxnum[2] = 29;
        return true;
    }else{
        return false;
    }
}

 2.判断输入日期是否正确,返回boolean值

public boolean checkInputValidity(){
    if(this.year<1900||this.year>2000||this.month<1||this.month>12||this.day<1||this.day>mon_maxnum[this.month]){
        return false;
    }else{
        return true;
    }
}

 3.计算下一天并输出

public void getNextDate(){
    day++;
    if(day>mon_maxnum[month]){
        day -= mon_maxnum[month];
        month++;
    }
    if(month>12){
        month = 1;
        year++;
    }
    System.out.print("Next day is:"+year+"-"+month+"-"+day);
}

主函数中创建对象调用对应方法,并对数据进行合理判断

Date date = new Date(year, month, day);
date.isLeapYear(year);
if(date.checkInputValidity()){
    date.getNextDate();
}else{
    System.out.print("Date Format is Wrong");
}

分析结束。

完整代码如下:

 import java.util.Scanner;

class Date{
    private int year;
    private int month;
    private int day;
    private int [] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};

    public Date() {

    }
    public Date(int year,int month,int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    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 boolean isLeapYear(int year){
        if( (year%4 == 0 && year%100 != 0) || year%400==0 ) {
            this.mon_maxnum[2] = 29;
            return true;
        }else{
            return false;
        }
    }
    public boolean checkInputValidity(){
        if(this.year<1900||this.year>2000||this.month<1||this.month>12||this.day<1||this.day>mon_maxnum[this.month]){
            return false;
        }else{
            return true;
        }
    }
    public void getNextDate(){
        day++;
        if(day>mon_maxnum[month]){
            day -= mon_maxnum[month];
            month++;
        }
        if(month>12){
            month = 1;
            year++;
        }
        System.out.print("Next day is:"+year+"-"+month+"-"+day);
    }
}
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int year = scan.nextInt();
        int month = scan.nextInt();
        int day = scan.nextInt();
        Date date = new Date(year, month, day);
        date.isLeapYear(year);
        if(date.checkInputValidity()){
            date.getNextDate();
        }else{
            System.out.print("Date Format is Wrong");
        }
    }
}

相关复杂度分析:

整体还可以依旧是不爱写注释,以后得改

相关类图:

 3-4 日期类设计

本题目标明确按照题目编写以下方法:

  • 设计一个类DateUtil
  • 1.public boolean checkInputValidity();                //检测输入的年、月、日是否合法
  • 2.public boolean isLeapYear(int year);                //判断year是否为闰年
  • 3.public DateUtil getNextNDays(int n);              //取得year-month-day的下n天日期
  • 4.public DateUtil getPreviousNDays(int n);        //取得year-month-day的前n天日期
  • 5.public boolean compareDates(DateUtil date);//比较当前日期与date的大小(先后)
  • 6.public boolean equalTwoDates(DateUtil date);//判断两个日期是否相等
  • 7.public int getDaysofDates(DateUtil date);        //求当前日期与date之间相差的天数
  • 8.public String showDate();                                  //格式返回日期值

本题只用写好类,先将类的属性,get,set方法和构造方法写出,然后对逐个实现所需方法

下面逐个分析每个方法

1.检测输入的年、月、日是否合法,返回boolean值

public boolean checkInputValidity(){
    if(isLeapYear(year)==true){
        mon_maxnum[2]=29;
    }else{
        mon_maxnum[2]=28;
    }
    if(this.year<1820||this.year>2020||this.month<1||this.month>12||this.day<1||this.day>mon_maxnum[this.month]){
        return false;
    }else{
        return true;
    }
}

2.判断year是否为闰年,返回boolean值

public boolean isLeapYear(int year){
    if( (year%4 == 0 && year%100 != 0) || year%400==0 ) {
        return true;
    }else{
        return false;
    }
}

3.取得year-month-day的下n天日期,返回对象

为防止传入的 day+=n 超过int所能存的最大值,使用递归分次对数据进行处理

public DateUtil getNextNDays(int n){
    if(isLeapYear(year)==true){
        mon_maxnum[2]=29;
    }else{
        mon_maxnum[2]=28;
    }
    if(n>2000000000){//int最大值会越界
        getNextNDays(2000000000);
        n -= 2000000000;
    }
    day+=n;
    while(day>mon_maxnum[month]){
        day -= mon_maxnum[month];
        month++;
        if(month==13){
            month -= 12;
            year++;
            if(isLeapYear(year)==true){
                mon_maxnum[2]=29;
            }else{
                mon_maxnum[2]=28;
            }
        }
    }
    return this;
}

 4.取得year-month-day的前n天日期,返回对象

public DateUtil getPreviousNDays(int n){
    int temp = day;
    day-=n;
    while(day<1){
        if(isLeapYear(year)==true){
            mon_maxnum[2]=29;
        }else{
            mon_maxnum[2]=28;
        }
        month--;
        if(month==0){
            month += 12;
            year--;
        }
        day += mon_maxnum[month];
    }
    return this;
}

5.比较当前日期与date的大小(先后),返回boolean值

public boolean compareDates(DateUtil date){
    if(this.year>date.year||(this.year==date.year&&this.month>date.month)||(this.year==date.year&&this.month==date.month&&this.day>date.day)) {
        return true;
    }else{
        return false;
    }
}

6.判断两个日期是否相等,返回boolean值

public boolean equalTwoDates(DateUtil date){
    if(this.year==date.year&&this.month==date.month&&this.day==date.day) {
        return true;
    }else{
        return false;
    }
}

7.求当前日期与date之间相差的天数,返回int型相差天数

//当时这个很多的地方有小问题,结果因为测试点太少了,混对了,现在回头才发现( ´◔︎ ‸◔︎`)//

public int getDaysofDates(DateUtil date){
        int tempday = date.day-this.day;
        if(this.month>date.month) {
            for (int i = date.month; i < this.month; i++) {
                if(isLeapYear(date.year)==true){
                    mon_maxnum[2]=29;
                }else{
                    mon_maxnum[2]=28;
                }
                tempday -= mon_maxnum[i];
            }
        }else {
            for (int i = this.month; i < date.month; i++) {
                if(isLeapYear(date.year)==true){
                    mon_maxnum[2]=29;
                }else{
                    mon_maxnum[2]=28;
                }
                tempday += mon_maxnum[i];
            }
        }
        if(this.year > date.year) {
            int tempyear = date.year;
            while(this.year>tempyear){
                tempyear++;
                if(isLeapYear(tempyear)) {
                    tempday -= 366;
                }else{
                    tempday-= 365;
                }
            }
        }else{
            int tempyear = this.year;
            while(date.year>tempyear){
                if(isLeapYear(tempyear)) {
                    tempday += 366;
                }else{
                    tempday += 365;
                }
                tempyear++;
            }
        }
        return tempday;
    }

8.格式返回日期值,返回格式化后的字符串

public String showDate(){
    return year+"-"+month+"-"+day;
}

 主函数题目给好了,直接合并使用

完整代码如下:

 import java.util.Scanner;

class DateUtil{
    private int year;
    private int month;
    private int day;
    private int [] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
    public DateUtil() {
    }
    public DateUtil(int year,int month,int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    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 boolean isLeapYear(int year){
        if( (year%4 == 0 && year%100 != 0) || year%400==0 ) {
            return true;
        }else{
            return false;
        }
    }
    public boolean checkInputValidity(){
        if(isLeapYear(year)==true){
            mon_maxnum[2]=29;
        }else{
            mon_maxnum[2]=28;
        }
        if(this.year<1820||this.year>2020||this.month<1||this.month>12||this.day<1||this.day>mon_maxnum[this.month]){
            return false;
        }else{
            return true;
        }
    }
    public DateUtil getNextNDays(int n){
        if(isLeapYear(year)==true){
            mon_maxnum[2]=29;
        }else{
            mon_maxnum[2]=28;
        }
        if(n>2100000000){//int最大值会越界
            getNextNDays(2100000000);
            n -= 2100000000;
        }
        day+=n;
        while(day>mon_maxnum[month]){
            day -= mon_maxnum[month];
            month++;
            if(month==13){
                month -= 12;
                year++;
                if(isLeapYear(year)==true){
                    mon_maxnum[2]=29;
                }else{
                    mon_maxnum[2]=28;
                }
            }
        }
        return this;
    }
    public DateUtil getPreviousNDays(int n){
        int temp = day;
        day-=n;
        while(day<1){
            if(isLeapYear(year)==true){
                mon_maxnum[2]=29;
            }else{
                mon_maxnum[2]=28;
            }
            month--;
            if(month==0){
                month += 12;
                year--;
            }
            day += mon_maxnum[month];
        }
        return this;
    }
    public boolean compareDates(DateUtil date){
        if(this.year>date.year||(this.year==date.year&&this.month>date.month)||(this.year==date.year&&this.month==date.month&&this.day>date.day)) {
            return true;
        }else{
            return false;
        }
    }
    public boolean equalTwoDates(DateUtil date){
        if(this.year==date.year&&this.month==date.month&&this.day==date.day) {
            return true;
        }else{
            return false;
        }
    }
    public int getDaysofDates(DateUtil date){
        int tempday = date.day-this.day;
        if(this.month>date.month) {
            for (int i = date.month; i < this.month; i++) {
                if(isLeapYear(date.year)==true){
                    mon_maxnum[2]=29;
                }else{
                    mon_maxnum[2]=28;
                }
                tempday -= mon_maxnum[i];
            }
        }else {
            for (int i = this.month; i < date.month; i++) {
                if(isLeapYear(date.year)==true){
                    mon_maxnum[2]=29;
                }else{
                    mon_maxnum[2]=28;
                }
                tempday += mon_maxnum[i];
            }
        }
        if(this.year > date.year) {
            int tempyear = date.year;
            while(this.year>tempyear){
                tempyear++;
                if(isLeapYear(tempyear)) {
                    tempday -= 366;
                }else{
                    tempday-= 365;
                }
            }
        }else{
            int tempyear = this.year;
            while(date.year>tempyear){
                if(isLeapYear(tempyear)) {
                    tempday += 366;
                }else{
                    tempday += 365;
                }
                tempyear++;
            }
        }
        return tempday;
    }
    public String showDate(){
        return year+"-"+month+"-"+day;
    }
}
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.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
            System.out.println(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.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
            System.out.println(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.println("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);
        }
    }
}

相关复杂度分析:

可以看出除了注释少了以外,程序的最大复杂度很高,以及平均分支嵌套的层数有点多,会影响可读性。

类图展示:

 

 采坑心得

在第二次题目集中大量使用浮点型数据,需要对其有一定的认识,

如float和double的有效精度范围,

float是单精度类型,精度是8位有效数字,double是双精度类型,精度是17位有效数字,

在2-8 判断三角形类型中体现较多,由于用double存储的数据并不是准确数值,所以需要用近似处理将误差消除,
在该题,我使用了DecimalFormat类格式化数据,将double型数据四舍五入消除误差。
 
也可以使用 两个double数据的差值小于0.00001时认为两者几乎相同 
如:
if(Math.abs(next-last)<=0.00001){

}

改进建议

后续编码过程中加强注释的合理使用,不怎么喜欢写方法,什么事都要主函数来干,复用性较差,不好阅读。¯\_(ツ)_/¯

总结

本次3个题目集作为Java入门的习题练习,主要为基本数据的运算,数字大小的排序,字符串的处理,日期的处理,对基本的逻辑能力有一定的考察,

对类有一个基本的了解,能够简单设计单个类,合理设计出相应的属性和方法。

 

posted @ 2023-03-26 17:32  22201335  阅读(21)  评论(1编辑  收藏  举报