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位有效数字,


if(Math.abs(next-last)<=0.00001){
}改进建议
后续编码过程中加强注释的合理使用,不怎么喜欢写方法,什么事都要主函数来干,复用性较差,不好阅读。¯\_(ツ)_/¯
总结
本次3个题目集作为Java入门的习题练习,主要为基本数据的运算,数字大小的排序,字符串的处理,日期的处理,对基本的逻辑能力有一定的考察,
对类有一个基本的了解,能够简单设计单个类,合理设计出相应的属性和方法。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号