OO第一次大作业

前言

前言的前言

这是我的第一篇blog,有点小激动,我还找教程设置了一下我的背景,本来还想弄个页面小宠物,但是看了一下感觉有点复杂,下次一定。如果对我blog的内容有任何修正或者建议可以评论让我知道,谢谢你愿意点开我的blog并给出建议🌹。

第一次作业

涉及知识点

基本数据类型、顺序结构、选择结构、循环结构、字符串、数组、数论、模拟。

题量

一共12题,看起来题量很大的样子,但是除了第10题,其他题目都比较简单,涉及的知识点也比较广泛,应该是为了让我们熟悉Java的基本语法,并没有出现类的使用。

难度

如上面所说的,除了第10题,其他题目都还是比较简单的,但是有一些小细节的地方也很容易出错,导致卡题。

关于题目的一些观点

1、对于第10题,我想多说两句,对于第10题使用的算法还是比较简单的,就是用String的一些基本操作,对处理过程进行模拟,我觉得第10题的难点主要还是在题目的理解上。
2、第11题我觉得不是很合理(个人观点,不喜勿喷),根据我的理解,题目应该是想要我们模拟定积分的运算过程。我先用高数知识直接对它积分,算出的结果很完美的通过了测试点。然后我按照题目的意思进行模拟,却一个点都没过,我知道模拟的结果会存在很大的误差,但我还是认为这个测试点不太符合题目想表达的意思。当然不排除我程序写错的可能性(后续有对拍的测试说明)。

第二次作业

涉及知识点

基本数据类型、数组、顺序结构、选择结构、字符串、模拟。

题量

一共9题,对比第一次作业题量少了,但是难度没有上升,应该还是为了让我们熟悉Java的基本语法。并且这次作业,每一个题目都有选择结构,我认为是一个对选择结构的强化训练。

难度

好玩不难,但是因为精度的问题被卡了好几题,最难的点我觉得是第8题中出现的浮点误差。值得一提的是,出现了需要写多个方法来解决问题的题目。

第三次作业

涉及知识点

构造类、LocalDate、顺序结构、选择结构、读类图。

题量

一共4题,题目量是最少的,第一次要求构造类,并且全部都是需要构造类,应该是关于构造类的强化训练。

难度

我个人认为难度一下就上来了,可能是我那时候还太不会构造类,虽然上课讲了,线上课程也有演示,但要我自己写的时候,一开始还是有点迷茫,不知道该怎么做。

三次作业总结

第一、二次作业都比较简单,题量比较大,旨在熟悉Java的语法。第三次作业难度就上来了,虽然题目量小,但花的时间是最多的,目的是熟悉怎么构造类。

设计与分析

写在前面

我主要是分析了第三次作业的代码的情况,因为第一次和第二次都只有主类和主方法,并且我在下面的踩坑心得里写的比较详细了。

7-1

源码数据

类图

源码

import java.util.Scanner;


class Circle{
    private double radius;

    public Circle(){

    }

    public Circle(double radius){
        this.radius = radius;
    }

    public double getter(){
        return this.radius;
    }

    public double setter(double radius) {
        return this.radius = radius;
    }

    public double getArea(){
        return Math.PI * Math.pow(this.radius,2);
    }
}

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        double r = input.nextDouble();
        Circle circle = new Circle(r);
        if(r < 0)
            System.out.println("Wrong Format");
        else{
            //circle.setter(r);
            System.out.printf("The circle's radius is:%.2f\n",circle.getter());
            System.out.printf("The circle's area is:%.2f\n",circle.getArea());
        }
    }
}

浅说几句

第一次用类来写程序,真的很煎熬,虽然听了老师的课,但是写起来还是不会,就只能又打开视频,跟着老师的讲解来模仿。画类图的时候,我发现我的setter居然是double类型,QAQ充分体现了初学者的憨憨操作。而且由于pta的特性,类只能在Main.java中构造,又在网上看了几篇文章才知道应该怎么写🥀。

7-2

源码数据

类图

源码

import java.util.Scanner;
import java.time.LocalDate;

class Account{
    private int id = 0;
    private double balance = 0.0;
    private double annualInterestRate = 0.0;
    private LocalDate dateCreated = LocalDate.of(2020,7,31);

    public Account(){

    }

    public Account(int id,double balance){
        this.id = id;
        this.balance = balance;
    }

    public int getId(){
        return this.id;
    }

    public void setId(int id){
        this.id = id;
    }

    public double getBalance(){
        return this.balance;
    }

    public void setBalance(double balance){
        this.balance = balance;
    }

    public double getAnnuallnterstRate(){
        return this.annualInterestRate;
    }

    public void setAnnuallnteratRate(double annualInterestRate){
        this.annualInterestRate = annualInterestRate;
    }

    public LocalDate getDateCreated(){
        return this.dateCreated;
    }

    public double getMonthlyInterestRate(){
        return (this.annualInterestRate / 1200) * this.balance;
    }

    public void withDraw(double getMoney){
        this.balance -= getMoney;
    }

    public void deposit(double bankMoney){
        this.balance += bankMoney;
    }
}

public class Main{
    
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        
        int id = input.nextInt();
        double balance = input.nextDouble();
        double annualInterestRate = input.nextDouble();
        double getMoney = input.nextDouble();
        double bankMoney = input.nextDouble();
        
        Account account = new Account(id,balance);
        //account.setId(id);
        //account.setBalance(balance);
        account.setAnnuallnteratRate(annualInterestRate);

        if(getMoney < 0 || getMoney > account.getBalance())
            System.out.println("WithDraw Amount Wrong");
        else
            account.withDraw(getMoney);
        if(bankMoney > 20000 || bankMoney < 0)
            System.out.println("Deposit Amount Wrong");
        else
            account.deposit(bankMoney);

        System.out.printf("The Account'balance:%.2f\n",account.getBalance());
        System.out.printf("The Monthly interest:%.2f\n",account.getMonthlyInterestRate());
        System.out.println("The Account'dateCreated:" + account.getDateCreated());
    }
}

浅说几句

这个程序写的时候明显比第一题顺手一点,有参和无参的构造方法都试着用了一下。浅浅了解了一下LocalDate这个类,发出了"Java好方便"的感叹。最后还想提一下运算的一个小坑(有同学被坑了),a * b / c 和 a * (b / c)在数学里面是一样的结果,但是在计算机里是不一样的,我个人认为也是浮点误差造成的,如果有不同的见解,欢迎评论🌹。

7-3

源码数据

类图

源码

import java.util.Scanner;

class Date{
    private int year;
    private int month;
    private int day;
    public  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 this.year;
    }

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

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

    public int getDay(){
        return this.day;
    }

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

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

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

    public void getNextDate(){
        if(this.day + 1 > mon_maxnum[month])
        {
            this.day = 1;
            if(this.month < 12)
                this.month++;
            else{
                this.month = 1;
                this.year++;
            }
        }
        else this.day++;
    }
}
public class Main {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        
        int year = input.nextInt();
        int month = input.nextInt();
        int day = input.nextInt();
        
        Date date = new Date(year,month,day);
        //date.setYear(year);
        //date.setMonth(month);
        //date.setDay(day);
        date.isLeapYear(year);
        if(!date.checkInputValidity()){
            System.out.println("Date Format is Wrong");
        }
        else {

            date.getNextDate();
            System.out.println("Next day is:" + date.getYear() + "-" + date.getMonth() + "-" + date.getDay());
        }
    }
}

浅说几句

这个题跟第二次作业的最后一题原理基本相同,就是把日期封装成了类,这题我也尝试了两种构造方法,都是OK的。

7-4

源码数据

类图

源码

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.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);
        }
    }
}
class DateUtil{
    private int year;
    private int month;
    private int day;
    protected int[] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};

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

    public int getYear() {
        return this.year;
    }
    public void setYear(int year){
        this.year = year;
    }
    public int getMonth() {
        return this.month;
    }
    public void setMonth(int month){
        this.month = month;
    }
    public int getDay() {
        return this.day;
    }
    public void setDay(int day){
        this.day = day;
    }
    public String showDate(){
        return this.year + "-" + this.month + "-" + this.day;
    }
    public boolean checkInputValidity(){
        if(year < 1820 || year > 2020)
            return false;
        else if(month < 1 || month > 12)
            return false;
        else if(day < 1 || day > mon_maxnum[month])
            return false;
        else  return  true;
    }
    public  boolean isLeapYear(int year){
        if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)){
            mon_maxnum[2] = 29;
            return true;
        }
        else {
            mon_maxnum[2] = 28;
            return false;
        }
    }
    public DateUtil getNextNDays(int n){
        //DateUtil date = new DateUtil(this.year,this.month,this.day);
        isLeapYear(this.year);
        while (n > 0){
            for(int i = this.month;i <= 12;i++) {
                if (n - (mon_maxnum[i] - this.day + 1) > 0) {
                    this.month += 1;
                    if (this.month > 12) {
                        this.month -= 12;
                        this.year += 1;
                        isLeapYear(this.year);
                    }
                    n -= mon_maxnum[i] - this.day + 1;
                    this.day = 1;
                } else {
                    this.day += n;
                    n -= n;
                    break;
                }
            }
        }
        return this;
    }
    public DateUtil getPreviousNDays(int n){
        isLeapYear(this.year);
        while (n > 0){
            for(int i = this.month;i >= 1;i--) {
                if (n - this.day > 0) {
                    this.month -= 1;
                    if (this.month < 1) {
                        this.month += 12;
                        this.year -= 1;
                        isLeapYear(this.year);
                    }
                    n -= this.day;
                    this.day = mon_maxnum[this.month];
                }
                else {
                    this.day -= n;
                    n -= n;
                    break;
                }
            }
        }
        return this;
    }
    public boolean compareDates(DateUtil date){
        if(this.year > date.year)
            return true;
        else if(this.year < date.year)
            return false;
        else {
            if(this.month > date.month)
                return true;
            else if(this.month < date.month)
                return false;
            else {
                if(this.day > date.day)
                    return true;
                else if(this.day < date.day)
                    return  false;
                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 sum1 = 0,sum2 = 0;
        int year = Math.min(date.year,this.year);
        int month = 1;
        int day = 1;
        if(equalTwoDates(date)) {
            return sum2 - sum1;
        }
        else {

            for (int i = year; i < date.year; i++) {
                if (isLeapYear(i)) {
                    sum1 += 366;
                } else sum1 += 365;
            }
            sum1 += date.day;
            isLeapYear(date.year);
            for(int i = 1;i < date.month;i++) {
                sum1 += mon_maxnum[i];
            }

            for (int i = year; i < this.year; i++) {
                if (isLeapYear(i)) {
                    sum2 += 366;
                } else sum2 += 365;
            }
            sum2 += this.day;
            isLeapYear(this.year);
            for (int i = month; i < this.month; i++) {
                sum2 += mon_maxnum[month];
            }
            //System.out.println(sum2 + " " + sum1);
            return Math.abs(sum2 - sum1);
        }
    }
}

浅说几句

这题是上一题的升级版,看起来很复杂,但是只要把问题拆分,变成三个问题,再逐一解决,就会简单一些。这题时间给的比较宽泛,所以计算前n天和后n天我都是前让日期加或减到下个月的第一天和前一个月的最后一天,然后再逐月处理。在跨年和二月的处理上遇到了一点问题,但是调试过程中很快就能发现。两天之差的计算出现的问题比较大,一开始我的算法是以较前的日期为起点,将计算后n天的代码,处理后逆用。幻想很美好,现实很残酷,计算结果跟样例差距很大。在跟一个实力远强于我的同学讨论后,发现可以沿用之前写过的计算时间差的题目的方法,以较前的年份的1月1日为起点,逐月分别计算到两个日期经过的天数,相减就是两个日期的天数差。

再说几句

这题有比较多同学找我帮了忙,我也从中发现了一些问题:
1、数据最大时,有的算法会超过int的范围,可以转用long存储,最后再转换成int
2、在判断闰年的时候,被判断的年份,到底是当年份还是最开始的年份
3、不是闰年时,2月的天数是否还原成28天

后期发现的问题

在进行第4次迭代的时候,发现了一些问题,这里对问题进行一下展示,给一份更新后的代码

很明显3月0日是不存在的,修改后如图

更新后的代码:

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.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);
        }
    }
}
class DateUtil{
    private int year;
    private int month;
    private int day;
    protected int[] mon_maxnum = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};

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

    public int getYear() {
        return this.year;
    }
    public void setYear(int year){
        this.year = year;
    }
    public int getMonth() {
        return this.month;
    }
    public void setMonth(int month){
        this.month = month;
    }
    public int getDay() {
        return this.day;
    }
    public void setDay(int day){
        this.day = day;
    }
    public String showDate(){
        return this.year + "-" + this.month + "-" + this.day;
    }
    public boolean checkInputValidity(){
        if(year < 1820 || year > 2020)
            return false;
        else if(month < 1 || month > 12)
            return false;
        else if(day < 1 || day > mon_maxnum[month])
            return false;
        else  return  true;
    }
    public  boolean isLeapYear(int year){
        if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)){
            mon_maxnum[2] = 29;
            return true;
        }
        else {
            mon_maxnum[2] = 28;
            return false;
        }
    }
    public DateUtil getNextNDays(int n){
        //DateUtil date = new DateUtil(this.year,this.month,this.day);
        isLeapYear(this.year);
        while (n > 0){
            for(int i = this.month;i <= 12;i++) {
                if (n - (mon_maxnum[i] - this.day + 1) > 0) {
                    this.month += 1;
                    if (this.month > 12) {
                        this.month -= 12;
                        this.year += 1;
                        isLeapYear(this.year);
                    }
                    n -= mon_maxnum[i] - this.day + 1;
                    this.day = 1;
                } else {
                    this.day += n;
                    n -= n;
                    break;
                }
            }
        }
        return this;
    }
    public DateUtil getPreviousNDays(int n){
        isLeapYear(this.year);
        while (n > 0){
            for(int i = this.month;i >= 1;i--) {
                if (n - this.day >= 0) {
                    this.month -= 1;
                    if (this.month < 1) {
                        this.month += 12;
                        this.year -= 1;
                        isLeapYear(this.year);
                    }
                    n -= this.day;
                    this.day = mon_maxnum[this.month];
                }
                else {
                    this.day -= n;
                    n -= n;
                    break;
                }
            }
        }
        return this;
    }
    public boolean compareDates(DateUtil date){
        if(this.year > date.year)
            return true;
        else if(this.year < date.year)
            return false;
        else {
            if(this.month > date.month)
                return true;
            else if(this.month < date.month)
                return false;
            else {
                if(this.day > date.day)
                    return true;
                else if(this.day < date.day)
                    return  false;
                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 sum1 = 0,sum2 = 0;
        int year = Math.min(date.year,this.year);
        int month = 1;
        int day = 1;
        if(equalTwoDates(date)) {
            return sum2 - sum1;
        }
        else {

            for (int i = year; i < date.year; i++) {
                if (isLeapYear(i)) {
                    sum1 += 366;
                } else sum1 += 365;
            }
            sum1 += date.day;
            isLeapYear(date.year);
            for(int i = 1;i < date.month;i++) {
                sum1 += mon_maxnum[i];
            }

            for (int i = year; i < this.year; i++) {
                if (isLeapYear(i)) {
                    sum2 += 366;
                } else sum2 += 365;
            }
            sum2 += this.day;
            isLeapYear(this.year);
            for (int i = month; i < this.month; i++) {
                sum2 += mon_maxnum[month];
            }
            //System.out.println(sum2 + " " + sum1);
            return Math.abs(sum2 - sum1);
        }
    }
}

踩坑心得

写在前面

我并没有对这三次作业的全部题目进行分析,毕竟有的题目真的很简单,几乎没有出错的地方,所以我只选取了我认为对我来说比较有价值的题目来分析。

第一次作业

7-1

问题

第一题确实不难,但是在控制小数位数卡了好久,题目给的数据计算结果恰好跟保留两位小数的结果一致,导致忽略了保留小数的操作,一直认为是边界值的问题,进行了大量尝试

解释和心得

从我下面的两张图片可以看出来,格式化输出后就好了。这个悲惨的故事告诉我们要仔细看题,理解它的一些潜在信息。我知道我这个代码很不规范(丑陋),已经在改啦!QAQ

import java.util.Scanner;
public class Main
{
    public static void main(String [] args)
    {
        Scanner input = new Scanner(System.in);
        long year = input.nextLong();
        double ans = 7.70;
        if(year <= 0)
        {
            System.out.print("error");
        }
        else
        {
            if(year <= 1)
                ans *= 0.5;
            else if(year <= 3)
                ans *= 0.7;
            else if(year <= 5)
                ans *= 1.0;
            else ans *= 1.1;
            System.out.print("实际利率="+ans+"%");
        }
    }
}

上面是没格式化输出的

import java.util.Scanner;
public class Main
{
    public static void main(String [] args)
    {
        Scanner input = new Scanner(System.in);
        long year = input.nextLong();
        double ans = 7.70;
        if(year <= 0)
        {
            System.out.print("error");
        }
        else
        {
            if(year <= 1)
                ans *= 0.5;
            else if(year <= 3)
                ans *= 0.7;
            else if(year <= 5)
                ans *= 1.0;
            else ans *= 1.1;
            System.out.printf("实际利率=%3.2f%%",ans);
        }
    }
}

上面是格式化输出的,有图有真相!
这里浅说一下%,因为%在printf中有特殊含义,所以要让它反义。如果感兴趣的话,你可以试试怎样才能输出"\x2333 为\a什\b么\r我\n签\n到\r题\b都\a过不了QAQ%",欢迎评论哦!

7-7

问题

在这个题目中,第一次出现“非零返回”,我去搜索了一下,大概了解到:“非零返回”就是程序异常中止,我这里应该是因为数组越界导致堆栈溢出。

解释和心得

为什么会数组溢出呢?我一看到题目就觉得好熟悉,跟桶排序的题目非常像,我就直接桶排序来记录数据出现的次数。后面发现每一个数的范围并没有给出,导致数组越界。

import java.util.Scanner;

public class Main
{
    public static void main(String [] args)
    {
        Scanner input = new Scanner(System.in);
        int flag =0;
        final int N = 100005;
        int [] book = new int [N];
        int n = input.nextInt();
        int [] arr = new int [n];
        for(int i = 0;i < n;i++)
        {
            arr[i] = input.nextInt();
            book[arr[i]]++;
            if(book[arr[i]]>1)
                flag=1;
        }
        if(flag == 1)
            System.out.print("YES");
        else System.out.print("NO");
    }
}

桶排序不行,我就开始模拟,果然t了。

import java.util.Scanner;

public class Main
{
    public static void main(String [] args)
    {
        Scanner input = new Scanner(System.in);
        
        int flag =0;
        int n = input.nextInt();
        int [] arr = new int [n];
        
        for(int i = 0;i < n;i++)
        {
            arr[i] = input.nextInt();
            if(flag == 0)
            {
                for(int j = 0;j < i;j++)
                {

                    if(arr[j] == arr[i])
                    {
                        flag = 1;
                        break;
                    }
                }
            }
        }
        if(flag == 1)
            System.out.print("YES");
        else System.out.print("NO");
    }
}

很明显这个算法的时间复杂度是O(n^2),不t才怪。联想到C++的sort(),作为C++好兄弟的Java不可能没有吧?

浅浅运用了一下

import java.util.Scanner;
import java.util.Arrays;

public class Main
{
    public static void main(String [] args)
    {
        Scanner input = new Scanner(System.in);
        
        int flag =0;
        int n = input.nextInt();
        int [] arr = new int [n];
        
        for(int i = 0;i < n;i++)
            arr[i] = input.nextInt();
        
        Arrays.sort(arr);
        
        for(int i = 1;i < n;i++)
        {
            if(arr[i]==arr[i-1])
            {
                System.out.print("YES");
                flag = 1;
                break;
            }
        }
        if(flag == 0)
            System.out.print("NO");
    }
}

7-10

问题:

这题也存在一些读题上的问题,题目明确说了,如果有多条满足题意的,输出最后一次的时间,但我的算法是找到了就输出,直接结束。

解释和心得

这个是错误代码

import java.util.Scanner;

public class Main
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        String s;

        while (true)
        {
            int sum = 0,text = 0;
            s = input.nextLine();
            if (s.equals("END"))
                break;
            if (s.indexOf("$GPRMC", 0) != -1 && s.indexOf(",A,", 0) != -1) {
                text = Integer.parseInt(s.substring(s.indexOf('*') + 1), 16);
                for (int i = 1; s.charAt(i) != '*'; i++) {
                    sum ^= s.charAt(i);
                }
                if (text == (sum %= 65536)) {
                    int t = Integer.parseInt(s.substring(s.indexOf(',') + 1, s.indexOf(',') + 7), 10);
                    //System.out.printf("%06d", t);
                    int ss = t % 100;
                    int mm = (t % 10000 - ss) / 100;
                    int hh = (t - mm * 100 - ss) / 10000 + 8;
                    if (hh >= 24)
                        hh -= 24;
                    System.out.printf("%02d:%02d:%02d", hh, mm, ss);
                    break;
                }
            }
        }
    }
}

正确的代码,就只改了输出的地方

import java.util.Scanner;

public class Main
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        String s;
        int ss = 0 , mm = 0 , hh = 0;
        while (true)
        {
            int sum = 0,text = 0;
            s = input.nextLine();
            if (s.equals("END"))
                break;
            if (s.indexOf("$GPRMC", 0) != -1 && s.indexOf(",A,", 0) != -1) 
            {
                text = Integer.parseInt(s.substring(s.indexOf('*') + 1), 16);
                for (int i = 1; s.charAt(i) != '*'; i++) 
                {
                    sum ^= s.charAt(i);
                }
                if (text == (sum %= 65536)) 
                {
                    int t = Integer.parseInt(s.substring(s.indexOf(',') + 1, s.indexOf(',') + 7), 10);
                    //System.out.printf("%06d", t);
                    ss = t % 100;
                    mm = (t % 10000 - ss) / 100;
                    hh = (t - mm * 100 - ss) / 10000 + 8;
                    if (hh >= 24)
                        hh -= 24;
                }
            }
        }
        System.out.printf("%02d:%02d:%02d", hh, mm, ss);
    }
}

这个题目主要是考察对String类里面一些方法的运用,比较:s.equals("")、查找:s.indexOf()、取字符串中的某个字符 s.charAt(i)等等。虽然,后面练习时我又忘了该怎么使用,但我不会像写这个题目一样对它们那么陌生。

7-11

解释和心得

这题本身没有对我来说没有问题,我主要想再说一下前面提到的模拟程序。我拿了两个程序对拍,结果如下图:
切分不那么细的运行结果

切分的更细的运行结果

可以看出来,在切分不够细的时候,两者误差比较大,在切分很细的时候,两者误差很小。我认为,这恰好说明了我的模拟程序是正确的,所以上述“程序存在问题”的情况可以排除。

第二次作业

7-6

问题

这题的问题我觉得主要有三个点,一个是读题,理解题目意思;另一个是在写循环的部分,一定要先计算一次再进循环,否则会导致无法进入循环。(这是我看到的别人的错误写法);最后一个就是近似的判断,由于浮点数在计算机中存储的特性,可知浮点数不能全等(==)。

解释和心得

这个题目,就很怪哈,我按照之前的经验,输出前强制转换了,还是不行。最后是把double全部改float才过的^ ^。

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        double n = input.nextDouble();
        double guess1 = input.nextDouble();
        double guess2;
        if(n < 0 || guess1 <= 0)
            System.out.print("Wrong Format");
        else{
            guess2 = (guess1 + n / guess1) / 2;
            while(Math.abs(guess1 - guess2) >= 0.00001)
            {
                guess1 = guess2;
                guess2 = (guess1 + n / guess1) / 2;
            }
            System.out.print((float)guess1);
        }
    }
}

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        float n = input.nextFloat();
        float guess1 = input.nextFloat();
        float guess2;
        if(n < 0 || guess1 <= 0)
            System.out.print("Wrong Format");
        else{
            guess2 = (guess1 + n / guess1) / 2;
            while(Math.abs(guess1 - guess2) >= 0.00001)
            {
                guess1 = guess2;
                guess2 = (guess1 + n / guess1) / 2;
            }
            System.out.print((float)guess1);
        }
    }
}

7-8

问题:

我在写的时候主要有两个问题,一个是等腰三角形的判断,另一个是等腰直角三角形的判断。等腰直角三角形的判断就涉及到浮点数判等的情况。

解释和心得

这是错误的代码,可以看到在判断等腰的时候,我只对a,b是否相等进行判断,但是很明显b,c也可能相等。(为什么我不说a,c也可能相等呢?因为我先对a,b,c进行了排序,a是最小的,c是最大的,如果a,c相等,那么b也与a,c相等,这时是等边三角形)在判断等腰直角时,我用的是全等,根据浮点数在计算机中的存储,很明显, Math.pow(c,2) == Math.pow(a,2) + Math.pow(b,2)这个条件是不可能满足的。

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        float a = input.nextFloat();
        float b = input.nextFloat();
        float c = input.nextFloat();
        
        if(a < 1 || a > 200 || b < 1 || b > 200 || c < 1 || c > 200){
             System.out.println("Wrong Format");
            return ;
        }
        else{
            if(a > b){
                float t;
                t = a;
                a = b;
                b = t;
            }
            if(b > c){
                float t;
                t = b;
                b = c;
                c = t;
            }
            if(a > c){
                float t;
                t = a;
                a = c;
                c = t;
            }
            if(a + b <= c || a + c <= b || b + c <= a){
                System.out.println("Not a triangle");
                return ;
            }
            if(a == b && b == c){
                System.out.println("Equilateral triangle");
                return ;
            }
            if(a == b && Math.pow(c,2) == Math.pow(a,2) + Math.pow(b,2)){
                System.out.println("Isosceles right-angled triangle");
                return ;
            }
            if(a == b && Math.pow(c,2) != Math.pow(a,2) + Math.pow(b,2)){
                System.out.println("Isosceles triangle");
                return ;
            }
            if(a != b && Math.pow(c,2) == Math.pow(a,2) + Math.pow(b,2)){
                System.out.println("Right-angled triangle");
                return ;
            }
            System.out.println("General triangle");
        }
    }
}

修改后代码如下

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        float a = input.nextFloat();
        float b = input.nextFloat();
        float c = input.nextFloat();
        
        if(a < 1 || a > 200 || b < 1 || b > 200 || c < 1 || c > 200){
             System.out.println("Wrong Format");
            return ;
        }
        else{
            if(a > b){
                float t;
                t = a;
                a = b;
                b = t;
            }
            if(b > c){
                float t;
                t = b;
                b = c;
                c = t;
            }
            if(a > c){
                float t;
                t = a;
                a = c;
                c = t;
            }
            if(a + b <= c || a + c <= b || b + c <= a){
                System.out.println("Not a triangle");
                return ;
            }
            if(a == b && b == c){
                System.out.println("Equilateral triangle");
                return ;
            }
            if(a == b && Math.abs(a * Math.pow(2,0.5) - c) < 0.000001){
                System.out.println("Isosceles right-angled triangle");
                return ;
            }
            if(a == b || b == c || a == c){
                System.out.println("Isosceles triangle");
                return ;
            }
            if(a != b && Math.pow(c,2) == Math.pow(a,2) + Math.pow(b,2)){
                System.out.println("Right-angled triangle");
                return ;
            }
            System.out.println("General triangle");
        }
    }
}

运行结果

7-9

问题

这题对我来说还是比较熟悉的,之前做过类似的,一开始就想到了用数组存储每个月的天数,算法也是没有问题的。为什么wa了这么多发呢?全是在调非法输入!!!😭

解释的心得

我最先的代码,可以看到,完全没有考虑到非法输入

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        int [] arr = {31,28,31,30,31,30,31,31,30,31,30,31};
        int year = input.nextInt();
        int month = input.nextInt();
        int day = input.nextInt();
        if((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)){
            arr[1]++;
        }
        if(day + 1 > arr[month - 1]){
            day = 1;
            if(month < 12)
                month++;
            else{
                year++;
                month = 1;
            }
        }
        else{
            day++;
        }
        System.out.println("Next date is:" + year + "-" + month + "-" + day);
    }
}

我没有分方法的AC代码

import java.util.Scanner;

public class Main{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        int [] arr = {31,28,31,30,31,30,31,31,30,31,30,31};
        int year = input.nextInt();
        int month = input.nextInt();
        int day = input.nextInt();
        if((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)){
            arr[1]++;
        }
        if(month < 1 || month > 12 || year < 1820 || year > 2020)
            System.out.println("Wrong Format");
        else{
            if(day > arr[month - 1] || day < 1)
                System.out.println("Wrong Format");
            else{
                if(day + 1 > arr[month - 1]){
                    day = 1;
                     if(month < 12)
                        month++;
                     else{
                        year++;
                        month = 1;
                    }
                }
            else{
                day++;
            }
                System.out.println("Next date is:" + year + "-" + month + "-" + day);
            }
        }
        
    }
}

因为那时候还不熟悉怎么调用方法,把主方法拆分后又wa了好几发。

这是我最后的代码,但是在判断这年是闰年之后,让 arr[1]++不好,应该arr[1] = 29,如果不是闰年就arr[1] = 28。

import java.util.Scanner;

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

第三次作业

第三次作业在语法上没有遇到什么困难,思路上的在"设计与分析"中说的都差不多了,我就不到这再写一次水字数了。

改进建议

1、第一次作业最大的问题就是,代码规范的问题,看到第二次和第三次作业的代码,能发现我已经在改进了,但还是有一些不足:不打注释,命名不够规范等等。我现在看我之前的代码,我也觉得好丑陋🥀。
2、我觉得我跟同学的交流还是太少了,虽然看起来我的测试点全部都过了,但是有的题目我会在一些小细节的地方出错,自己找bug一直找不到,白白浪费了时间。况且,测试点并不能完全覆盖,也不能测出你的算法优劣,我还是要多跟同学交流,多多学习,当然不仅仅是练习的题目,还有更多的"思维碰撞"。
3、我觉得我现在还是练得太少,学习也不够规范,总是习惯去网上找文章直接看某个知识点,而不是踏踏实实从书上一点点积累。我们现在的教程被叫做"Java字典",我觉得很形象,不认识的"字"就是应该去查"字典"。
4、浅看了一下我的文章,我很多次提到类似"不仔细"的字眼,主要反映在写代码和读题上,或许我应该减少对IDEA实时报错的依赖。
5、要更多的尝试去测试程序的边界,进行一些异常处理,让自己的代码健壮性更强,不会轻易被测试数据打倒💪。

总结

浅浅获得的一些知识

浅浅学会了一点点类的内容,基本的语法之类的。总的来说,我会的东西还是太少了,每次练习都能学到新的东西,这当然很好,能学到新的东西我也很快乐,学习就是一点一滴积累的过程。但我还是比较期待,我发现我好像没有学到什么新东西的那一天。

需要进一步学习的知识

我觉得最需要的就是系统的学习,在空闲的时候应该多花一点时间在看系统的视频课。并且,在学习的过程中最需要的是"知其然,知其所以然"。就像老师说的:"我们学的是专业,哪有那么简单"。

一点小小的建议

1、关于pta的测试点,我有几句想说的:
我认为,结果为小数的答案,应该更加明确,比如规定保留几位小数,或者答案设置成区间,如果用户的数据跟测试点误差小于1e-6就认为相等之类的。在第二次作业中,就有很多题目是因为精确度的问题被卡题。
2、未完,可能再续……

posted @ 2023-03-26 00:31  clear_tea  阅读(158)  评论(5)    收藏  举报