1.前言

(1)OOP训练集04:知识点主要是数据的处理、应用和输出,封装性的应用,日期类的应用,菜单题很考验对类如何进行合理的设计,题量有点多。我认为的重点是菜单题和两道对重复数据的处理,处理重复数据时运行超时是最头疼的。

(2)OOP训练集05:前四道有三道都是对正则表达式的考察,一道考察字符串的处理,剩下两道稍微有点难度,是之前的日期题的迭代,考察面向对象程序设计的聚合。我认为这次作业是没什么难度的,最后两道虽然比较长,但是有之前的基础,只是稍微有点花时间,还是写得出来的。

(3)OOP训练集06:只有一道菜单题,但是因为训练集04那道没写出来,了很久都没头绪,最后没在规定时间写出来。。。这道题进一步考察如何进行合理设计,需要考虑的点非常多

2.设计与分析

 

(1)训练集04 7-4 单词统计与排序

我的思路:

拿到这道题最主要的是想怎么将输入的文本分割,卡在这一步卡了很久,不知道怎么才能除去文本中的“,”“.”" "把单词提取出来,后来想到先用replaceAll方法将,.换成空格,再利用split方法把文本拆分成没有空格的字符串数组。

接着按照题意利用for循环和if语句进行比较和交换顺序,最后利用列表输出,为了使重复单词只输出一次,创建新列表,如果列表中有要输出的单词,那就不输出,如果没有,输出并加入列表。

我的代码:

import java.util.ArrayList;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String sentence = input.nextLine().replaceAll("[,.]","");//把所有的,和.换成空字符
        String[] word = sentence.split(" ");//拆分成没有空格的字符串数组


        String w;
        for(int i = 0;i < word.length;i++){
            for(int j = 0;j < word.length-i-1;j++){
                if(word[j].length()<word[j+1].length()){//如果前一个单词长度小于后一个
                    w = word[j];
                    word[j] = word[j+1];
                    word[j+1] = w;//交换
                } else if (word[j].length() == word[j+1].length()) {//如果单词长度相等,比较字母
                    for(int m = 0;m < word[j].length();m++){
                        if(word[j].substring(m,m+1).compareToIgnoreCase(word[j+1].substring(m,m+1))>0){//如果字母前一个大于后一个
                            w = word[j];
                            word[j] = word[j+1];
                            word[j+1] = w;//交换
                            break;
                        } else if (word[j].substring(m,m+1).compareToIgnoreCase(word[j+1].substring(m,m+1))<0) {//如果小于
                            break;//直接结束
                        }
                    }
                }
            }
        }

        ArrayList<String> printWords = new ArrayList<>();
        for (int i = 0; i < word.length; i++) {
            if(!printWords.contains(word[i])){//如果列表中不存在该元素
                System.out.println(word[i]);//输出
                printWords.add(word[i]);//将该元素加入列表
            }
        }
    }
}

(2)训练集05 日期问题面向对象设计(聚合一)

 我的思路:

 这道题是之前日期问题的迭代,观察类图后认为应该先从year类开始写,依次写Month,Day,DateUtil,Main类,内容和之前的题目是差不多的,只需要稍作调整修改,主要就是考察聚合。

我的代码:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();//输入选择
        if(choice == 1){//选择1求下n天
            int year = input.nextInt();
            int month = input.nextInt();
            int day = input.nextInt();
            DateUtil date = new DateUtil(day, month, year);//输入年月日
            int n = input.nextInt();//输入n
            if(n<0){
                System.out.println("Wrong Format");
            }else {
                if(date.checkInputValidity()){
                    System.out.println(date.getNextNDays(n).showDate());//求下n天
                }else {
                    System.out.println("Wrong Format");
                }
            }
        } else if (choice == 2) {//选择2求前n天
            int year = input.nextInt();
            int month = input.nextInt();
            int day = input.nextInt();
            DateUtil date = new DateUtil(day, month, year);//输入年月日
            int n = input.nextInt();//输入n
            if(n<0){
                System.out.println("Wrong Format");
            }else {
                if(date.checkInputValidity()){
                    System.out.println(date.getPreviousNDays(n).showDate());//求前n天
                }else {
                    System.out.println("Wrong Format");
                }
            }
        } else if (choice == 3) {//选择3求两个日期相差天数
            int year1 = input.nextInt();
            int month1 = input.nextInt();
            int day1 = input.nextInt();
            int year2 = input.nextInt();
            int month2 = input.nextInt();
            int day2 = input.nextInt();
            DateUtil date1 = new DateUtil(day1, month1, year1);//输入date1年月日
            DateUtil date2 = new DateUtil(day2, month2, year2);//输入date2年月日
            if(date1.checkInputValidity() && date2.checkInputValidity()){
                System.out.println(date1.getDaysofDates(date2));//求相差天数
            }else {
                System.out.println("Wrong Format");
            }
        }else {//输入无效
            System.out.println("Wrong Format");
        }
    }
}

class DateUtil {
    private Day day;

    public DateUtil() {
    }
    public DateUtil(int d, int m, int y) {
        this.day = new Day(y,m,d);
    }

    public Day getDay() {
        return day;
    }
    public void setDay(Day d) {
        this.day = d;
    }

    //校验数据合法性
   public boolean checkInputValidity(){
        return day.getMonth().validate()&&day.validate()&&day.getMonth().getYear().validate();//年月日都合法返回true,否则返回false
   }

   //比较两个日期的大小,date1<date2返回true,反之返回false
    public boolean compareDates(DateUtil date){
        if(day.getMonth().getYear().getValue() < date.getDay().getMonth().getYear().getValue()){//date1年小于date2年
            return true;
        } else if (day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&
                day.getMonth().getValue() < date.getDay().getMonth().getValue()) {//年相同但date1月更小
            return true;
        } else return day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue() &&
                day.getMonth().getValue() == date.getDay().getMonth().getValue() &&
                day.getValue() < date.getDay().getValue();//年月相同但date1日更小
    }

    //判定两个日期是否相等
    public boolean equalTwoDates(DateUtil date){
        return day.getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue()&&
                day.getMonth().getValue() == date.getDay().getMonth().getValue() &&
                day.getValue()==date.getDay().getValue();//年月日都相同
    }

    //日期格式化
    public String showDate(){
        return day.getMonth().getYear().getValue()+"-"+day.getMonth().getValue()+"-"+day.getValue();
    }

    //求下n天
    public DateUtil getNextNDays(int n){
        while(n>365){
            if(day.getMonth().getYear().isLeapYear()){
                n=n-365;
                day.getMonth().getYear().yearIncrement();
            }
            else{
                n=n-366;
                day.getMonth().getYear().yearIncrement();
            }
        }
        for (int i = 1; i<=n; i++) {
            if (day.getMonth().getValue() == 12 && day.getValue() == 31) {//一年的最后一天
                day.getMonth().getYear().yearIncrement();
                day.getMonth().resetMin();
                day.resetMin();
            } else if (day.getValue() == day.getMon_maxnum()) {//每月最后一天
                day.getMonth().monthIncrement();
                day.resetMin();
            } else {//其它的日期
                day.dayIncrement();
            }
        }
        showDate();
        return new DateUtil(day.getValue(),day.getMonth().getValue(),day.getMonth().getYear().getValue());
    }

    //求前n天
    public DateUtil getPreviousNDays(int n){
        while(n>365){
            if(day.getMonth().getYear().isLeapYear()){
                n=n-365;
                day.getMonth().getYear().yearReduction();
            }
            else{
                n=n-366;
                day.getMonth().getYear().yearReduction();
            }
        }
        for (int i = 1; i<=n; i++) {
            if (day.getMonth().getValue() == 1 && day.getValue() == 1) {//一年的第一天
                day.getMonth().getYear().yearReduction();
                day.getMonth().resetMax();
                day.resetMax();
            } else if (day.getValue() == 1) {//每月第一天
                day.getMonth().monthReduction();
                day.resetMax();
            } else {//其它的日期
                day.dayReduction();
            }
        }
        showDate();
        return new DateUtil(day.getValue(),day.getMonth().getValue(),day.getMonth().getYear().getValue());
    }

    //求两个日期之间的天数
    public int getDaysofDates(DateUtil date){
        int n=0;//相差的天数
        if(equalTwoDates(date)){//相等
            return n;
        } else if (compareDates(date)) {//date1<date2
            while(!equalTwoDates(date)){
                if(day.getMonth().getValue() == 12 && day.getValue() == 31){//一年的最后一天
                    day.getMonth().getYear().yearIncrement();
                    day.getMonth().resetMin();
                    day.resetMin();
                }else if(day.getValue() == day.getMon_maxnum()) {//每月最后一天
                    day.getMonth().monthIncrement();
                    day.resetMin();
                }else {//其他的日期
                    day.dayIncrement();
                }
                n++;
            }
            return n;
        } else{//当前天数>date
            while(!equalTwoDates(date)){
                if (day.getMonth().getValue() == 1 && day.getValue() == 1) {//一年的第一天
                    day.getMonth().getYear().yearReduction();
                    day.getMonth().resetMax();
                    day.resetMax();
                } else if (day.getValue() == 1) {//每月第一天
                    day.getMonth().monthReduction();
                    day.resetMax();
                } else {//其它的日期
                    day.dayReduction();
                }
                n++;
            }
            return n;
        }
    }
}

class Day {
    private int value;
    private Month month;
    private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31};


    public Day() {
    }

    public Day(int yearValue, int monthValue, int dayValue) {
        this.value = dayValue;
        this.month = new Month(yearValue,monthValue);
    }

    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }

    public Month getMonth() {
        return month;
    }
    public void setMonth(Month month) {
        this.month = month;
    }

    public int getMon_maxnum(){
        if(!month.getYear().isLeapYear()){//如果是闰年
            mon_maxnum[1] = 29;//2月最大日期改为29
        }else {
            mon_maxnum[1] = 28;//否则2月还是28天
        }
        return mon_maxnum[month.getValue()-1];
    }

    //日期复位(1)
    public void resetMin(){
        value = 1;
    }

    //日期设为该月最大值
    public void resetMax(){
        value = getMon_maxnum();
    }

    //校验数据合法性
    public boolean validate(){
        return value >= 1 && value <= getMon_maxnum();//合法返回true,不合法返回false
    }

    //日期增1
    public void dayIncrement(){
        value = value + 1;
    }

    //日期减1
    public void dayReduction(){
        value = value - 1;
    }

}


class Month {
    private int value;
    private Year year;


    public Month() {
    }
    public Month(int yearValue, int monthValue) {
        this.value = monthValue;
        this.year = new Year(yearValue);
    }

    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }

    public Year getYear() {
        return year;
    }
    public void setYear(Year year) {
        this.year = year;
    }

    //月份复位(1)
    public void resetMin(){
        value = 1;
    }

    //月份设置为12
    public void resetMax(){
        value = 12;
    }

    //校验数据合法性
    public boolean validate(){
        return value>=1&&value<=12;//合法返回true,不合法返回false
    }

    //月份增1
    public void monthIncrement(){
        value = value + 1;
    }

    //月份减1
    public void monthReduction(){
        value = value - 1;
    }
}


class Year {
    private int year;

    public Year() {
    }
    public Year(int value) {
        this.year = value;
    }

    public int getValue() {
        return year;
    }
    public void setValue(int value) {
        this.year = value;
    }

    //判断是否为闰年
    boolean isLeapYear(){
        return !(year % 4 == 0 && year % 100 != 0 || year % 400 == 0);//是平年返回true,不是平年返回false
    }

    //检验数据合法性
    boolean validate(){
        return year>=1900&&year<=2050;//合法返回true,不合法返回false
    }

    //年份增1
    void yearIncrement(){
        year = year + 1;
    }

    //年份减1
    void yearReduction(){
        year = year - 1;
    }

}

(3)训练集05 7-6 日期问题面向对象设计(聚合二)

 我的思路:

 这道题是之前日期题的另一种迭代,另一种聚合方式,Year,Month,Day类在这里是一种“平级关系",按照类图来写也很容易,先把Day,Month,Year类写好,再将其它补充完整,依然可以直接复制之前的代码。

我的代码:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();//输入选择
        if(choice == 1){//选择1求下n天
            int year = input.nextInt();
            int month = input.nextInt();
            int day = input.nextInt();
            DateUtil date = new DateUtil(new Year(year), new Month(month), new Day(day));//输入年月日
            int n = input.nextInt();//输入n
            if(n<0){
                System.out.println("Wrong Format");
            }else {
                if(date.checkInputValidity()){
                    System.out.println(year+"-"+month+"-"+day+" next "+n+" days is:"+date.getNextNDays(n).showDate());//求下n天
                }else {
                    System.out.println("Wrong Format");
                }
            }
        } else if (choice == 2) {//选择2求前n天
            int year = input.nextInt();
            int month = input.nextInt();
            int day = input.nextInt();
            DateUtil date = new DateUtil(new Year(year), new Month(month), new Day(day));//输入年月日
            int n = input.nextInt();//输入n
            if(n<0){
                System.out.println("Wrong Format");
            }else {
                if(date.checkInputValidity()){
                    System.out.println(year+"-"+month+"-"+day+" previous "+n+" days is:"+date.getPreviousNDays(n).showDate());//求前n天
                }else {
                    System.out.println("Wrong Format");
                }
            }
        } else if (choice == 3) {//选择3求两个日期相差天数
            int year1 = input.nextInt();
            int month1 = input.nextInt();
            int day1 = input.nextInt();
            int year2 = input.nextInt();
            int month2 = input.nextInt();
            int day2 = input.nextInt();
            DateUtil date1 = new DateUtil(new Year(year1), new Month(month1), new Day(day1));//输入date1年月日
            DateUtil date2 = new DateUtil(new Year(year2), new Month(month2), new Day(day2));//输入date2年月日
            if(date1.checkInputValidity() && date2.checkInputValidity()){
                System.out.println("The days between "+year1+"-"+month1+"-"+day1+" and "+year2+"-"+month2+"-"+day2+" are:"
                        +date1.getDaysofDates(date2));//求相差天数
            }else {
                System.out.println("Wrong Format");
            }
        }else {//输入无效
            System.out.println("Wrong Format");
        }
    }
}

class DateUtil {
    private Year year;
    private Month month;
    private Day day;
    private int[] mon_maxnum = {31,28,31,30,31,30,31,31,30,31,30,31};


    public DateUtil() {
    }
    public DateUtil(Year year, Month month, Day day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public Year getYear() {
        return year;
    }
    public void setYear(Year year) {
        this.year = year;
    }

    public Month getMonth() {
        return month;
    }
    public void setMonth(Month month) {
        this.month = month;
    }

    public Day getDay() {
        return day;
    }
    public void setDay(Day day) {
        this.day = day;
    }

    public int[] getMon_maxnum() {
        if(!year.isLeapYear()){//如果是闰年,2月改为29天,否则不变
            mon_maxnum[1] = 29;
        }else {
            mon_maxnum[1] = 28;
        }
        return mon_maxnum;
    }

    //设置日期最小值(1)
    public void setDayMin(){
        day.setValue(1);
    }

    //设置日期最大值(当月最大天数)
    public void setDayMax(){
        day.setValue(getMon_maxnum()[month.getValue()-1]);
    }

    //校验输入数据合法性
    public boolean checkInputValidity(){
        return month.validate() && day.getValue() >= 1 && day.getValue() <= getMon_maxnum()[month.getValue()-1] && year.validate();
    }

    //求下n天
    public DateUtil getNextNDays(int n){
        while(n>365){
            if(year.isLeapYear()){
                n=n-365;
                year.yearIncrement();
            }
            else{
                n=n-366;
                year.yearIncrement();
            }
        }
        for (int i = 1; i<=n; i++) {
            if (month.getValue() == 12 && day.getValue() == 31) {//一年的最后一天
                year.yearIncrement();
                month.resetMin();
                setDayMin();
            } else if (day.getValue() == getMon_maxnum()[month.getValue()-1]) {//每月最后一天
                month.monthIncrement();
                setDayMin();
            } else {//其它的日期
                day.dayIncrement();
            }
        }
        showDate();
        return new DateUtil(year,month,day);
    }

    //求前n天
    public DateUtil getPreviousNDays(int n){
        while(n>365){
            if(year.isLeapYear()){
                n=n-365;
                year.yearReduction();
            }
            else{
                n=n-366;
                year.yearReduction();
            }
        }
        for (int i = 1; i<=n; i++) {
            if (month.getValue() == 1 && day.getValue() == 1) {//一年的第一天
                year.yearReduction();
                month.resetMax();
                setDayMax();
            } else if (day.getValue() == 1) {//每月第一天
                month.monthReduction();
                setDayMax();
            } else {//其它的日期
                day.dayReduction();
            }
        }
        showDate();
        return new DateUtil(year,month,day);
    }

    //判定两个日期的先后,date1<date2返回true,反之返回false
    public boolean compareDates(DateUtil date){
        if(year.getValue() < date.year.getValue()){//date1年小于date2年
            return true;
        } else if (year.getValue() == date.year.getValue()&& month.getValue() < date.month.getValue()) {//年相同但date1月更小
            return true;
        } else return year.getValue() == date.year.getValue() && month.getValue() == date.month.getValue() &&
                day.getValue() < date.getDay().getValue();//年月相同但date1日更小
    }

    //判定两个日期是否相等
    public boolean equalTwoDates(DateUtil date){
        return year.getValue() == date.year.getValue() && month.getValue() == date.month.getValue() &&
                day.getValue() == date.getDay().getValue();//年月日都相同
    }

    //求两个日期的天数差
    public int getDaysofDates(DateUtil date){
        int n=0;//相差的天数
        if(equalTwoDates(date)){//相等
            return n;
        } else if (compareDates(date)) {//date1<date2
            while(!equalTwoDates(date)){
                if(month.getValue() == 12 && day.getValue() == 31){//一年的最后一天
                    year.yearIncrement();
                    month.resetMin();
                    setDayMin();
                }else if(day.getValue() == getMon_maxnum()[month.getValue()-1]) {//每月最后一天
                    month.monthIncrement();
                    setDayMin();
                }else {//其他的日期
                    day.dayIncrement();
                }
                n++;
            }
            return n;
        } else{//当前天数>date
            while(!equalTwoDates(date)){
                if (month.getValue() == 1 && day.getValue() == 1) {//一年的第一天
                    year.yearReduction();
                    month.resetMax();
                    setDayMax();
                } else if (day.getValue() == 1) {//每月第一天
                    month.monthReduction();
                    setDayMax();
                } else {//其它的日期
                    day.dayReduction();
                }
                n++;
            }
            return n;
        }
    }

    //日期按“年-月-日”格式化
    public String showDate(){
        return year.getValue()+"-"+month.getValue()+"-"+day.getValue();
    }

}

class Year {
    private int value;


    public Year() {
    }
    public Year(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }


    //判断闰年
    public boolean isLeapYear(){
        return !(value % 4 == 0 && value % 100 != 0 || value % 400 == 0);//平年返回true,闰年返回false
    }

    //数据合法性校验
    public boolean validate(){
        return value >= 1820 && value <= 2020;
    }

    //年增1
    public void yearIncrement(){
        value = value + 1;
    }

    //年减1
    public void yearReduction(){
        value = value - 1;
    }
}

class Month {
    private int value;

    public Month() {
    }
    public Month(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }

    //月份复位(1)
    public void resetMin(){
        value = 1;
    }

    //月份设置最大值(12)
    public  void resetMax(){
        value = 12;
    }

    //数据合法性校验
    public boolean validate(){
        return value >= 1 && value <= 12;
    }

    //月增1
    public void monthIncrement(){
        value = value + 1;
    }

    //月减1
    public void monthReduction(){
        value = value - 1;
    }
}

class Day {
    private int value;

    public Day() {
    }
    public Day(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }

    //日增1
    public void dayIncrement(){
        value = value + 1;
    }

    //日减1
    public void dayReduction(){
        value = value - 1;
    }
}

(4)训练集04 7-1,训练集06 7-1

由于我的拖延没能写完菜单题我深感愧疚,在此先分析我目前已有的思路,完成菜单题后我将会重新编辑这个博客(虽然也不知道对没对就是了。。)

 我的思路:

 首先要考虑是怎么把输入的一大串字符串按照需求分开,思考过后认为要用正则表达式来实现。然后开始画类图,除了题中给的几个类,另外我加上了Table类,根据题目要求,属性有桌号、用餐时间、点菜记录、代点菜信息、删除信息。还加上Time类,属性有calendar。这几个类用来进行输入信息的储存,另外还要有类来判断各种情况,从而进行输出。在写的过程中发现Menu类中的属性和方法可以用static进行修饰,因为在一次输入中,菜单是共有的。

点菜信息的储存用的是列表,因为并不能确定输入的点菜信息数量,也方便后面删除信息,储存是直接按照输入的序号进行储存。

这道题我写的很没有计划,我拿到这道题时我不知道该从哪里开始,在画类图的时候犹豫了很久,类与类之间的关系判断不出来,于是就一直卡着,后来按照一个暂定的类图开始写,但还是没有什么思路。

代码是半成品,就不展示了。

3.踩坑心得

(1)首先是训练集04的7-2和7-3两道对重复数据的处理

我的做法:

 这样写是能够得出结果的,但是当输入大量数据时会运行超时,每次作业有关这种需要对循环进行改进的题目我都写不来。。

(2)

训练集05中的7-5 7-6 判断日期合法性会出现问题,由于&&会按顺序进行判断,而且在day的判断中用到了每月最大天数的数组,如果先判断day,当输入的月份超过12,数组会超限,所以要先判断月份,当月份超过12时,会直接返回false。

 4.改进建议

要找到一个能够优化循环的方法,来应对大量数据的处理。最重要的是菜单题,在写的过程中我感觉到我的类图是有问题的,而且没有符合一些设计原则,菜单题不仅要写完,还要改进。

5.总结

这三次作业与上三次作业对比难度升了很多,不再是单纯java语法的应用,更需要自己去学会合理设计类,没能写出菜单题我很愧疚也很遗憾,我认为那是一道很具挑战性的题目,如果能够成功写出来会很有成就感。当然我不打算放弃,我会把菜单题写出来。但我有一个建议,下次这样的迭代的题目还是希望可以从最初的最简单的开始,我们的菜单题是直接从3开始的,如果写过1和2,应该会更有思路吧。