Java初步学习记录(pta作业集总结01-03)

Java初步学习记录

一、前言

以下开始针对前三次Java pta作业集做出以下总结(任务罢了( ̄▽ ̄)):
这三次次所做的pta作业整体而言有一定难度,并且每次均做出了时间的限制,短短几周内就通过学从的经验把Java的基本语法基本掌握不得不说有一定难度。01题目集总共题量比较大,直接给初学者的我一个狠狠的下马威,不过题目难度还可以,不需要花费过多的时间,其中几道基础题目用于学习基本的输入输出条件循环语法,而后几道题目针对于Java中字符串的处理,稍微麻烦一点,但出的比较浅显,而gps那道题目着实让人没有做的欲望,题目太长了,看都不想看。02题目集虽然题目多,但总体跨度不大,都是Java基本语法的训练,还可以。03题目集跨度比较大,需要专门去学习Java中的一大特色封装,并且对于类和对象需要有一定的理解,而且最后一题的测试点比较全面,故而对应的代码需要不断的完善,很花费时间。

二、设计与分析

1、题目集01

大多都是比较简单的题目,不过其中字符串和语言大有不同,需要重点学习,比较有代表性的就是7-8题了。

7-8 从一个字符串中移除包含在另一个字符串中的字符

作者 殷伟凤 单位 浙江传媒学院
题目描述:从一个字符串中移除包含在另一个字符串中的字符。输入两行字符串,将第一行字符串中包括第二行字符串中的所有字母去除。输出去除后保留的字符串。

输入格式:

第一行输入一个字符串
第二行输入一个字符串

输出格式:

输出移除后的字符串

输入样例:

在这里给出一组输入。例如:

abcdefghijklmnopqrstuvwxyz  
secret  

输出样例:

在这里给出相应的输出。例如:

abdfghijklmnopquvwxyz  
代码长度限制                              16 KB  
时间限制                                 400 ms
内存限制                                  64 MB  

Steps:初次学习Java,对于其中的字符串对象不太熟悉,尤其是字符串类是无法改变的这一特性,与c语言大相径庭。故我先去查如何改变原字符串的类,而后使用StringBuffer做完了该题。
Ideas:定义一个StringBuffer类str获得第一个输入,而后再定义一个String类s1获得对比的字符串。而后再通过循环对str中有无s1字符串中单个字符(通过substring方法截取至字符串compare中)进行比对(indexOf方法),而后用StringBuffer中deleteCharAt方法删除指定下标的字符即可。

while(i < length){//length为字符串s1的长度
    compare = s1.substring(i,i+1);
    index = str.indexOf(compare);
    while(index != -1){//直到str中不再含有指定字符
        str.deleteCharAt(index);
        index = str.indexOf(compare);
    }
    i++;
}

由于难度不大所有测试点一遍就能够过了,不过该题还能先转化我字符数组(toCharArray方法),而对于熟悉的字符数组进行查改操作比较简单,此处不过多赘述。
以下为源代码

import java.util.*;
public class Main {
    public static void main(String[] args) {
        String s,s1;
        int i = 0,index = 0,length;
        String compare;
        Scanner input = new Scanner(System.in);
        s = input.nextLine();
        s1 = input.nextLine();
        StringBuffer str=new StringBuffer("");
        str.append(s);
        length = s1.length();
        while(i < length){
            compare = s1.substring(i,i+1);
            index = str.indexOf(compare);
            while(index != -1){
                str.deleteCharAt(index);
                index = str.indexOf(compare);
            }
            i++;
        }
        System.out.print(str);
    }
}

2、题目集02

相较于第一次难度有了不小的提升,不过对个人而言写起来比第一次顺手不少,除了7-8浪费了一些时间,其他的都比较快就解决了,或许现在开始是有了一点基础的原因( ╯▽╰),此处7-7由于开始一直想通过StringBuffer类写也花费了不少时间。

7-7 二进制数值提取

作者 蔡轲 单位 南昌航空大学
题目描述:在一个字符串中提取出其中的二进制数值序列。

输入格式:

一个由0、1构成的序列,以-1为结束符,非0、1字符视为正常输入,但忽略不计,未包含结束符的序列视为非法输入。例如:abc00aj014421-1

输出格式:

将输入的序列去掉非0、1字符以及结尾符的数据内容,
注:结束符-1之后的0\1字符忽略不计。
例如:00011。

输入样例:

在这里给出一组输入。例如:

abc00aj014421-1

输出样例:

在这里给出相应的输出。例如:

00011

输入样例1:

在这里给出一组输入。例如:

a0571-1k001y

输出样例1:

在这里给出相应的输出。例如:

01
代码长度限制                              16 KB  
时间限制                                 400 ms
内存限制                                  64 MB  

Steps:由于对于删改的惯性思维,开始比较倾向于使用StringBuffer类进行删改操作,意图通过对于“0”,“1”,“-1”字符串的查找来逐步消除“0”,“1”,字符,但麻烦点在于“-1”字符串中同样含有“1”字符串,而且其中对于“-1”不在末尾的情况会报错,因此改变思路,通过对原字符串中的字符提取出来逐步检查,符合要求的字符便加到新字符串s1中,最后输出s1即可。对于修改前的代码我会放到踩坑心得中讲解。
Ideas:定义一个String类s(接收输入)和s1(输出结果)。利用循环获得s中的每一个字符(charAt方法),不过每次需要获得两个字符,专门用于判断“-1”字符串,字符a获得第i位,字符b获得第i+1位,而后判断是否位上述字符中的一个即可,条件为真则将该字符a加到s1中,最后输出s1。

while(i < s.length()-1){
    a = s.charAt(i);
    b = s.charAt(i+1);
    if(a == '0' || a == '1'){
        s1 += a;
    }else if(a == '-' && b == '1'){
        flag = 1;//判断是否有结束符从而调整输出
        break;
    }
    i++;
}

将思路更改后代码简单很多,而且比较容易看懂,写起来比较顺。测试点也是一遍就能过。所以在有时候卡题目时,适当更换思路可能有奇效。
以下为源代码

import java.util.*;
public class Main {
    public static void main(String[] args) {
        String s,s1 = "";
        int i = 0,flag = 0;char a,b;
        Scanner input=new Scanner(System.in);
        s=input.nextLine();
        while(i < s.length() - 1){
            a = s.charAt(i);
            b = s.charAt(i + 1);
            if(a == '0' || a == '1'){
                s1 += a;
            }else if(a == '-' && b == '1'){
                flag = 1;
                break;
            }
            i++;
        }
        if(flag == 1){
            System.out.print(s1);
        }else{
            System.out.print("Wrong Format");
        }
    }
}

3、题目集03

这次的题目集03难度上升了一个大档次,对于Java本身的特色封装做了很大的要求,而且需要完全理解类的定义和使用,以及如何通过需求去定义对象的个体和功能。在此之前,我对于Java中的类的概念其实非常模糊,所以做的过程比较折磨。刚开始就连第一题都弄了比较久,一直在查百度。不过通过去b站看了Java关于类和对象的网课后,一切都豁然开朗了,譬如getter以及setter的实际意义是什么,以及类的一般定义方法和具体实现,了解这些后写起来就顺手很多了,网课的链接放在下面,需要的可以看看。
https://www.bilibili.com/video/BV17F411T7Ao/?spm_id_from=333.337.search-card.all.click&vd_source=cab4352f0bd29a40ec8786615f500d5d
由于前两道题目在了解类和对象的定义后比较简单,此处仅讲解7-3和7-4两道比较麻烦的题目。

7-3 定义日期类

作者 段喜龙 单位 南昌航空大学
题目描述:定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:

输入格式:

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

输出格式:

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

输入样例1:

在这里给出一组输入。例如:

1912 12 25

输出样例1:

在这里给出相应的输出。例如:

Next day is:1912-12-26

输入样例2:

在这里给出一组输入。例如:

2001 2 30

输出样例2:

在这里给出相应的输出。例如:

Date Format is Wrong
代码长度限制                              16 KB  
时间限制                                 400 ms
内存限制                                  64 MB  

Steps:既然是需要定义类和对象的题目,自然需要先把类的关系和功能弄清楚。而类图在题目中已经给出。通过类图我们可以清晰明了的知道所定义的类中该包含哪些要素,以及彼此之间的关系。此外,对于其中的setter和getter方法以及无参和有参构造法能够通过idea中的快捷键快速生成,按住写好类中的个体后按住fn+alt+insert键

这样一个比较完整的类的基本定义已经完成,后续就是对于Date类的功能进行分析了并创建即可完成。
Ideas:首先是isLeapYear方法的创建,功能为分析一个年份是否为闰年,if条件判断即可,能被400整除或者呗4整除不被100整除的即为闰年。

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

而后分析checkInput方法,对于类中的年月份检查是否符合题目规范,年月份没什么好说的,日份通过类中定义的mon_maxnum判断即可,注意闰年的二月份总天数需要+1。

public boolean checkInputValidity(){
    if(isLeapYear(year)){//闰年二月份总天数加1
        mon_maxnum[2]++;
    }
    if(year < 1900 || year > 2000){
        return false;
    }else{
        if(month < 1||month > 12){
            return false;
        }else{
            if(day>mon_maxnum[month] || day < 1){
                return false;
            }else{
                return true;
            }
        }
    }
}

最后便是获得下一天的方法了,判断day+1后是否会超过对于月份总天数即可,条件为真月份+1并且让day=1,再判断月份+1后是否大于12,条件为真month=1,年份+1。

public void getNextDate(){
    if(day+1 > mon_maxnum[month]){
        day = 1;
        month++;
    }else{
        day++;
    }
    if(month > 12){
        month = 1;
        year++;
    }
}

由于基本方法都放上去了,源代码就不贴了,以免过长o( ̄ヘ ̄o#),接下来是最为繁琐的7-4。

7-4 日期类设计

作者 段喜龙 单位 南昌航空大学
题目描述:参考题目3和日期相关的程序,设计一个类DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 除了创建该类的构造方法、属性的getter及setter方法外,需要编写如下方法:

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

应用程序共测试三个功能:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
(主方法代码比较长,我们这里不做讲解,主要研究类方法如何构建)

输入格式:

有三种输入方式(以输入的第一个数字划分[1,3]):

  • 1 year month day n //测试输入日期的下n天
  • 2 year month day n //测试输入日期的前n天
  • 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数

输出格式:

  • 当输入有误时,输出格式如下:
Wrong Format
  • 当第一个数字为1且输入均有效,输出格式如下:
  year1-month1-day1 next n days is:year2-month2-day2
  • 当第一个数字为2且输入均有效,输出格式如下:
  year1-month1-day1 previous n days is:year2-month2-day2
  • 当第一个数字为3且输入均有效,输出格式如下:
  The days between year1-month1-day1 and year2-month2-day2 are:值

输入样例1:

在这里给出一组输入。例如:

3 2014 2 14 2020 6 14

输出样例1:

在这里给出相应的输出。例如:

The days between 2014-2-14 and 2020-6-14 are:2312

输入样例2:

在这里给出一组输入。例如:

2 1834 2 17 7821

输出样例2:

在这里给出相应的输出。例如:

1834-2-17 previous 7821 days is:1812-9-19

输入样例3:

在这里给出一组输入。例如:

1 1999 3 28 6543

输出样例3:

在这里给出相应的输出。例如:

1999-3-28 next 6543 days is:2017-2-24

输入样例4:

在这里给出一组输入。例如:

0 2000 5 12 30

输出样例4:

在这里给出相应的输出。例如:

Wrong Format
代码长度限制                              12 KB  
时间限制                                 10000 ms
内存限制                                  64 MB  

Steps:和先前Date类的创建方法类似,先构思好对于的类图,如下所示

而后再逐一将其中的方法实现即可。

Ideas:从下n天方法开始,有了先前求一天的方法,其实n天可以参考先前写过的下一天方法,让其循环n次即可。不过此处我想到了其他的算法从时间效率上会更高一点,由于n可能很大,所以需要考虑n>365后年份+1的情况,也需要考虑每个月份最大总天数。首先,如果通过n对减去年总天数,那么我们自然就需要看下一年是闰年或者平年来减去不同的年天数,个人感觉麻烦就放弃了。而后我便考虑按月份计算的方法,比如3月10日的后25天,易知10+25>31(3月份总天数),故月份+1。我们day的计算方法就是10+25-31(3月份的总天数),故结果为4月4日。然后再扩展到n>一个月的总月数的情况,3月10日的后100天,计算方法同理,10+100>31故月份+1.....因而我们得出循环的条件为day+n>mon_maxnum[month],循环内部为day+n-=mon_maxnum[month]。至此,该方法基本完成,代码如下。

public DateUtil getNextNDays(int n){
    //day+=n;//去掉”//“后为原始代码
    while(n > mon_maxnum[month]){
        isLeapYear(year);
        n -= mon_maxnum[month];
        month++;
        if(month > 12){
            month = 1;
            year++;
        }
    }
    //因为测试点有一个数据n恰好为int类型的最大值,不能对n进行相加(会爆int),所以改成先n循环后再把day加上去。
    day += n;
    if(day > mon_maxnum[month]){
        day -= mon_maxnum[month];
        month++;
        if(month > 12){
            month = 1;
            year++;
        }
    }
    return this;
}

由求下n天的方法,我们很容易退出前n天的方法,将day+n改为day-n,循环条件改为day<=0即可,剩下的原理相同,代码如下

public DateUtil getPreviousNDays(int n){
    day -= n;
    while(day <= 0){
        isLeapYear(year);
        day += mon_maxnum[month-1];
        month--;
        if(month < 1){
            month = 13;
            year--;
        }
    }
    return this;
}

比较日期大小的方法直接if-else级联语句即可完成,代码如下

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

接下来为比较日期相同方法,同样能直接判断即可。

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

注意: 接下来就是整道题比较巧妙的一点了。当一个类中方法较多时,可以思考下这些方法之间是否有什么联系,例如先前的判断闰年方法,在其它方法中同样多次用到。而在这个方法中,我们需要计算两个日期的差值,那么开始,肯定需要用到前面的compareDates 方法,不仅如此,既然我们前面写好了求下n天的方法,那么我们是否能通过让其中较小的日期一直通过getNextNDays 方法向下走一天,而当两个日期相等时equalTwoDates方法返回值为真时,退出循环。这样便完美的利用了前面的方法,并且能快速简便的将getDaysofDates 方法写完,代码如下

public int getDaysofDates(DateUtil date){
    int n = 0;
    if(equalTwoDates(date)){
        return 0;
    }else{
        if(compareDates(date)){
            while(true){
                date = date.getNextNDays(1);
                n++;
                if(equalTwoDates(date)){
                    break;
                }
            }
        }else{
            while(true){
                date = date.getPreviousNDays(1);
                n++;
                if(equalTwoDates(date)){
                    break;
                }
            }
        }
    }
    return n;
}

最后一个String showDate方法是最为简单的,按照输出格式定义一个String类将各个体链接起来即可,代码如下

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

上面已经将题目所需的大部分方法源代码给出,此处便不在贴所有源码 φ(-ω-*)。

三、踩坑心得

题目集02

7-7二进制数值提取

修改思路前,按照StringBuffer类删改的代码如下

import java.util.*;
public class Main {
    public static void main(String[] args) {
        StringBuffer s1,s2;String s;
        int index=0,index1=0,length=-1,compare=0;
        Scanner input=new Scanner(System.in);
        s=new String();
        s1=new StringBuffer("");
        s2=new StringBuffer("");
        s=input.nextLine();
        s1.append(s);//将s字符串加至s1
        length=s1.indexOf("-1");//循环前先获得一次字符串中目标字符的位置
        index=s1.indexOf("0");
        index1=s1.indexOf("1");
        while(compare<length){//当匹配的"0"或者"1"字符的位置大于“-1”时退出循环
            length=s1.indexOf("-1");
            index=s1.indexOf("0");
            index1=s1.indexOf("1");
            //本质问题出现在循环判断条件上
            if(length==0){
                break;
            }
            if(index==-1){
                index=length;
            }else if(index1==-1){
                index1=length;
            }
            if(index<index1){//判断先加“0”还是“1”字符串
                s2.append("0");
                s1.delete(0,index+1);
            }else{
                s2.append("1");
                s1.delete(0,index1+1);
            }
        }
        if(length==-1){
            System.out.print("Wrong Format");
        }else{
            System.out.print(s2);
        }
    }
    public static  int min(int a,int b){
        if(a>b){
            return b;
        }else{
            return a;
        }
    }
}

其实当时就错了一两种情况,但始终难以找出问题,如以下输入,运行后的输出就不符合要求。因此被迫更改了思路,改用字符判断的方式解决。
图片Alt

题目集02

7-8判断三角形类型

这题当时没一次过的问题就是栽在了等腰直角三角形上,一直将等腰直角三角形判断成等腰三角形导致有几个点出错,如下所示
图片Alt
之后试了直角三角形的测试,同样出现问题后,我便能肯定是直角的判定方式出了问题,原先的判定条件如下

if(b*b+c*c==a*a){
    return true;
}else{
    return false;
}

突然发现浮点数类型就算二者相乘也无法和整数2符合相等的条件,故判断条件永远为假,自然便输出了等腰三角形的结果。
于是将条件稍作修改,既然无法相等,但二者的值是非常接近的,只要二者的差值小于某个很小的常数,那么我就能近似认为两者相等,修改后如下

if(Math.abs(b*b+c*c-a*a)<0.01){
    return true;
}else{
    return false;
}

问题成功解决,同时学到浮点数之间计算的判断不能单纯的使用“==”运算符,需要使用其他的方法。

四、改进建议

其实大部分代码由于当初c语言的习惯没改,所以写的比较不规范,命名有些地方也有不少的问题,不过出去写法不规范的问题,绝大部分代码的逻辑或者算法基本没什么可改的了,这里针对7-4题的求n天介绍下另一种比较耗时间但看起来更为美观的将getNextDate方法循环n次的方法

while(n > 0){
    this = this.getNextDate;
    n--; 
}
return this;

这种方法虽然比较耗时间,但并不存在n超过限制的可能性,继承性和泛用性也比较好。

五、总结

不得不承认,虽然两个星期内写完这三次的题目集压力比较大(毕竟每天的课程非常之多╮(╯▽╰)╭),但是这一轮下来收获也是比较多的,从0基础到现在基本了解对象和类,Java的进展很快。学会了Java前期的基本语法,不过对于Java中的字符串类的使用仍然学的不精,需要继续深入学习。

此外,对于老师完全放养式的方法,个人认为有利有弊吧,毕竟有的时候碰到一些看不懂的bug是真的要浪费好多时间嘞(*  ̄︿ ̄),当然具体的一些改进建议个人认为没什么可提的,大部分都还行,就是觉得作业其实可以稍微减少a litteX﹏X。

posted @   混日子的小羊  阅读(135)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
返回顶端
点击右上角即可分享
微信分享提示