OPP前三次作业总结
前言:
前三次oop训练集的题目量不多,前三次题量总计25题,难度也是旨在让我们从易到难来理解,自学java的语法,所以难度适中。
第一次OPP训练集:
第一次训练集集中于让我们熟悉java的语法,很多题目其实都用C语言写过了,难度不是很大。
第二次OPP训练集:
第二次训练集主要集中训练我们的逻辑思维,其中的大量题目都要运用各种判断来解题。
第三次OOP训练集:
-第一次训练集主要考察类的创建和规范,其中7-3,7-4两题难度相对其他题目要难一些,但是7-3的代码可以用在7-4上,可以检验你的代码是否可以重复利用,是否有可持续性。
第一次OOP训练:
7-7 有重复的数据
设计与分析:
设计
将整数存入数组,在将数组从小到大排序,在用循环比对相邻的两个数,如果相同则输出NO,如果比对到最后则输出YES
分析
一开始我写的是将数组中的整数与这个数前的所有数比对,后来发现运行超时,所以这种暴力比对是不行的,后来改用排序后。只要比对相邻两数就可以了,大大减少时间复杂度。
具体代码
点击展开查看代码
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int a=in.nextInt();
int []b=new int[a];
for(int i=0;i<a;i++)
{
b[i]=in.nextInt();
}
boolean f=true;
Arrays.sort(b);
for(int i=0;i<a;i++)
{
if(i==a-1)break;
if(b[i]==b[i+1])
f=false;
}
if(f==true)
System.out.println("NO");
else
System.out.println("YES");
}
}
生成报表
踩坑心得
一开始一直运行超时,这道题需要效率更高的方法来解题。这类只需要输出结果YES,NO的,就可以用这种排序的方法。遇到运行超时这种错误的话,需要及时更改解题算法。
改进建议
这题其实可以创造一个类出来,并且把代码写的更规范,这样在后续类似的题目中,能够重复利用代码,做到可持续性。
7-8 从一个字符串中移除包含在另一个字符串中的字符
设计与分析:
设计
将两行输入存入字符数组,将第一行的字符数组一个个与第二行的比较,如果都不相同,则追加到新的字符序列上。
分析
这种题目一看就有,我就有两种解题思路,一种在原有的基础上减去相同的,一种是追加不同的。而我选的第二种,那么就要用到StringBuffer类中的append()方法,在用toSring()转换成字符串输出。
具体代码
点击展开查看代码
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
String aa=in.nextLine();
String bb=in.nextLine();
char a[]=aa.toCharArray();
char b[]=bb.toCharArray();
boolean f=true;
int La=aa.length();
int Lb=bb.length();
StringBuffer sb=new StringBuffer();
for(int i=0;i<La;i++)
{
f=true;
for(int j=0;j<Lb;j++)
{
if(a[i]==b[j])
{
f=false;
break;
}
}
if(f==true)
{
StringBuffer sb1=sb.append(a[i]);
}
}
String s=sb.toString();
System.out.println(s);
}
}
生成报表
踩坑心得
一开始是没有想到用StringBuffer类中的append()方法的,因为刚开始用Java写作业,对Java中的类不熟,后来在CSDN了解java各种常用类与方法的时候看到后,也是毫不犹豫的用这个办法来解题,了解多一点的类与方法,而且要去在实际题目中去运用它,这样可以很高的提高做题效率,可能一开始的时候会很慢,但是也是一种积累的办法。
改进建议
这题一样,书写不规范,可读性很低,不利于后期的改进和持续性开发。这题也可以与上一题写进一个关于数组的去重的类中,做到持续开发完善。
第二次OOP训练集:
7-8 判断三角形类型
设计与分析:
设计
将输入的三条边先进行合法判断,在进行各种三角型的逻辑判断
分析
三角形类型判断就要运用好勾股定理,并且有的三角形有着包含关系,就像等腰直角三角型包含在等腰三角型中,要合理的减少代码量,做到简洁,可读。
具体代码
点击展开查看代码
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
float a=in.nextFloat();
float b=in.nextFloat();
float c=in.nextFloat();
if(a<1||a>200||b<1||b>200||c<1||c>200){
System.out.print("Wrong Format");
return;
}
if((a+b)<=c||(a+c)<=b||(b+c)<=a){
System.out.print("Not a triangle");
return;
}
else{
if(a==b&&b==c){
System.out.print("Equilateral triangle");
return;
}//(a==b||b==a||c==a)&&(Pow(a)+Pow(b)==Pow(c)||Pow(c)+Pow(b)==Pow(a)||Pow(a)+Pow(c)==Pow(b))
else if((a==b&&Pow(a)+Pow(b)-Pow(c)<0.000001)||(b==c&&Pow(c)+Pow(b)-Pow(a)<0.000001 )||(a==c&&Pow(a)+Pow(c)-Pow(b)<0.000001)){
System.out.print("Isosceles right-angled triangle");
return;
}
else if((Pow(a)+Pow(b)==Pow(c)||Pow(c)+Pow(b)==Pow(a)||Pow(a)+Pow(c)==Pow(b))){
System.out.print("Right-angled triangle");
return;
}
else if((a==b||b==c||c==a)){
System.out.print("Isosceles triangle");
return;
}
else{
System.out.print("General triangle");
return;
}
}
//System.out.print(Pow(2));
//System.out.print(a+" "+b+" "+c);
}
public static float Pow(float a){
return a*a;
}
}
生成报表
踩坑心得
有个坑卡了我很久,就是直角三角型的判断,大家都知道直角三角型的判断就是a2+b2=c2,所以我的代码也是这样写的,但是提交后一直报错。一直看代码也没有发现错误。后来才发现计算机的计算与我们人的计算不一样,这是因为计算机中对于浮点数的计算方式而导致的问题。例如0.1+0.7=0.7999999999999999。所以我会一直卡在直角三角形这。只需要将判断改为在误差在0.000001之内就可以过了。另外这种逻辑类题目一定要保持好可读性,因为我在报错之后修改或者隔一段时间再来继续写的话,会减慢你写的速度,因为你的可读性太差或者没有注释的话,就要重新去看逻辑,重新跟上写的思路。
改进建议
这题应该创建一个判断三角形类型的类,做到重复利用。可读性比第一次作业高一点了,但仍然可以改进。
7-9 求下一天
设计与分析:
设计
获取数据后先判断是否合法,然后判断是否为闰年,再判断是否为月末,年末。
分析
这题的要点就是月末和年末要改变月和年,并且还有闰年的二月是29天这些都是这题注意的点。题目难度不大,但注重逻辑和细节的考察。
具体代码
点击展开查看代码
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int year=in.nextInt();
int month=in.nextInt();
int day=in.nextInt();
boolean f=true;
boolean Run=false;
if(checkInputValidity(year,month,day)){
nextDate(year,month,day);
}
else{
System.out.print("Wrong Format");
return;
}
}
public static boolean isLamonth(int month){
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){
return true;
}
else{
return false;
}
}
public static boolean isLeapYear(int year){
if((year%4==0&&year%100!=0)||(year%400==0)){
return true;
}
else{
return false;
}
}
public static boolean checkInputValidity(int year,int month,int day){//||(day>=1&&day<=31)
if((year>=1820&&year<=2020)&&(month>=1&&month<=12)){
if(isLamonth(month)&&(day>=1&&day<=31)){
return true;
}
else if(month==2&&(day>=1&&day<=29)&&isLeapYear(year)){
return true;
}
else if(month==2&&(day>=1&&day<=28)&&!isLeapYear(year)){
return true;
}
else if(!isLamonth(month)&&(month!=2)&&(day>=1&&day<=30)){
return true;
}
}
return false;
}
public static void nextDate(int year,int month,int day){
if(month==2){
if((day==29&&isLeapYear(year))||(day==28&&!isLeapYear(year)) ){
System.out.print("Next date is:"+year+'-'+(month+1)+"-"+"1");
}
else if((month!=29&&isLeapYear(year))||(month!=28&&!isLeapYear(year))){
System.out.print("Next date is:"+year+'-'+month+"-"+(day+1)) ;
}
}
else{
if((isLamonth(month)&&day==31)||(!isLamonth(month)&&day==30) ){
if(month==12){
System.out.print("Next date is:"+(year+1)+'-'+"1"+"-"+"1");
return;
}
System.out.print("Next date is:"+year+'-'+(month+1)+"-"+"1");
}
else if((isLamonth(month)&&day!=31)||(!isLamonth(month)&&day!=30) ){
System.out.print("Next date is:"+year+'-'+month+"-"+(day+1));
}
}
}
}
生成报表
踩坑心得
这题难度较低,要注意的就是闰年的判断和月末,年末的下一天是不一样的。这题我在写的时候出现的错误就是非法数据的判断条件写错了,这是一个细节问题,改了之后直接过了,所以题目不难,认真写很容易过的。
改进建议
这题写的太乱了,很多可以放到一起的逻辑判断我给分开了,代码冗长,而且可读性很低,并且没有合理的用注释解释,应该在必要的地方用注释解释,这样在后期改进,开发的时候减少时间,提高效率。
第三次OOP训练集:
7-3 定义日期类
设计与分析:
类图:
分析
这题主要考察我们根据类图来编写类,以为第一次接触类,所以题目不难,但是要注意的是代码的可读性和可持续性,想下一题也是日期类的题目,这个类写的规不规范,就看能不能直接放到下一题运用,在我看来,这才是一个好的代码设计。
具体代码
点击展开查看代码
import java.util.Scanner;
class Date{
private int year=0;
private int month=0;
private int day=0;
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%4==0&&year%100!=0)||year%400==0){
return true;
}
else{
return false;
}
}
public boolean checkInputValidity(){
if(this.year>=1900&&this.year<=2000){
if(isLeapYear(year)){
setFebruaryMaxDay(month);
}
if(this.month>=1&&this.month<=12){if(this.day>=1&&this.day<=mon_maxnum[this.month]){
return true;
}
else{
return false;
}
}
else{
return false;
}
}
else{
return false;
}
}
public void getNextDate(){
if(this.day==this.mon_maxnum[month]){
if(this.month==12){
this.year=this.year+1;
this.month=1;
this.day=1;
}
else{
this.month=this.month+1;
this.day=1;
}
}
else{
this.day=this.day+1;
}
}
public void setFebruaryMaxDay(int month){
this.mon_maxnum[2]=29;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int year=in.nextInt();
int month=in.nextInt();
int day=in.nextInt();
Date date =new Date(year,month,day);
if(!date.checkInputValidity()){
System.out.println("Date Format is Wrong");
return;
}
else{
date.getNextDate();
System.out.print("Next day is:"+date.getYear()+"-"+date.getMonth()+"-"+date.getDay());
}
}
}
踩坑心得
这一题难度不大,但是要注意很多细节,我提交的第一次以为年的合法范围写错,一个小的细节卡了挺久的。所以我认为软件的特殊性就是没有过程分,只有运行和运行不了两种结果,就算再厉害的技术也要注重细节,不然真的会浪费很多时间去处理这些“很简单”的错误。另外即使能够通过,也要把代码写的易读,易修改。方便下一次重复利用这个类,提高效率。
改进建议
这是第一次写类,当时代码的书写规范还是不错的,就是其中checkInputValidity()方法的书写还是太乱了,可读性低,可以改进。
7-4 日期类设计
设计与分析:
类图:
分析
这题可以延用上一题的代码进行扩写,同样的类进行扩写,解决不同的问题,这题有三种情况:
第一种:输出输入日期的下n天
第二种:输出输入日期的前n天
第三种:输出两个日期之间相差的天数
这三种题目的解题思路都差不多,唯一需要注意的就是闰年的二月是29天,具体思路就是将n天与365天比较,再与各个月的天数比较,这样可以减小时间复杂度。
具体代码
点击展开查看代码
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=0;
private int month=0;
private int day=0;
public int mon_maxnum[]=new int[]{31,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 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 checkInputValidity(){//检测输入的年、月、日是否合法
if(this.year>=1820&&this.year<=2020){
if(isLeapYear(year)){
setFebruaryMaxDay(this.month);
}
if(this.month>=1&&this.month<=12){
if(this.day>=1&&this.day<=mon_maxnum[this.month]){
return true;
}
else{
return false;
}
}
else{
return false;
}
}
else{
return false;
}
}
public boolean isLeapYear(int year){//判断year是否为闰年
if((year%4==0&&year%100!=0)||year%400==0){
return true;
}
else{
return false;
}
}
public DateUtil getNextNDays(int n){//取得year-month-day的下n天日期
while(n>(mon_maxnum[month]-day)){
if(isLeapYear(year)){
mon_maxnum[2]=29;
}
else{
mon_maxnum[2]=28;
}
n=n-(mon_maxnum[month]-day);
day=0;
month++;
if(month>12){
year+=1;
month=1;
}
}
day=day+n;
DateUtil nextNDay = new DateUtil(year,month,day);
return nextNDay;
}
public DateUtil getPreviousNDays(int n){//取得year-month-day的前n天日期
int yearP=year;
int monthP=month;
int dayP=day;
while(n>=mon_maxnum[monthP]||n>=dayP){
if(isLeapYear(yearP)){
mon_maxnum[2]=29;
}
else{
mon_maxnum[2]=28;
}
n=n-(mon_maxnum[monthP-1]);
monthP--;
if(monthP==0){
yearP-=1;
monthP=12;
}
}
dayP=dayP-n;
DateUtil previousNDay = new DateUtil(yearP,monthP,dayP);
return previousNDay;
}
public boolean compareDates(DateUtil date){//比较当前日期与date的大小(先后)//先大为真
if(this.year>date.year){
return true;
}
else if(this.year==date.year){
if(this.month>date.month){
return true;
}
else if(this.month==date.month){
if(this.day>=date.day){
return true;
}
return false;
}
return false;
}
return false;
}
public boolean equalTwoDates(DateUtil date){//判断两个日期是否相等
if(this.year==date.year&&this.month==date.month&&this.day==date.day){
return true;
}
return false;
}
public int getDaysofDates(DateUtil date){//求当前日期与date之间相差的天数
int differDay=0;
int biggerYear;
int biggerMonth;
int biggerDay;
int smallerYear;
int smallerMonth;
int smallerDay;
if(equalTwoDates(date)){
return 0;
}
if(compareDates( date)){
biggerYear=this.year;
biggerMonth=this.month;
biggerDay=this.day;
smallerYear=date.year;
smallerMonth=date.month;
smallerDay=date.day;
}
else{
biggerYear=date.year;
biggerMonth=date.month;
biggerDay=date.day;
smallerYear=this.year;
smallerMonth=this.month;
smallerDay=this.day;
}
while(biggerYear>smallerYear){
if(isLeapYear(smallerYear)){
differDay+=366;
}
else{
differDay+=365;
}
smallerYear+=1;
}
while(biggerMonth>smallerMonth){
if(isLeapYear(smallerYear)){
mon_maxnum[2]=29;
}
else{
mon_maxnum[2]=28;
}
differDay+=mon_maxnum[smallerMonth];
smallerMonth+=1;
}
while(biggerMonth
生成报表
踩坑心得:
如图,这题我写的时候出现的bug就是内存不足,我换了各种算法依然不行,到最后开始寻找各种减小内存的方法是发现,一开始DateUtil类的属性,年,月,日都是用Integer来定义,然而Integer占28字节堆内存,而int仅占4字节堆内存。知道原因后难怪会内存超限。后来就改了这一个地方这题就直接满分了,所以我真的发现细节和基础知识的积累很重要。就因为这个内存超限我就花了2个小时的时间去解决,幸好最后也是过了。
改进建议
这一题用到了上一题所写的代码,当时不能直接使用,所以代码写的没有很严谨,换了个环境可能就不能用了,所以可以在其中常用的方法中将其改的更严谨,更易修改,遵循单一原则,每个方法只做一件事,显然这题写的代码并没有全部遵循,但可以改进,让代码呈现高内聚,低耦合。
总结:
这三次训练集从易到难,也是为了让我们熟悉java,所以题目难度整体偏低,在我写题,回顾的时候,也发现了自身的几个大问题,第一点就是不太细心,其中很多题出现的BUG都是因为疏忽大意,没有注重细节导致的。第二点就是基础知识不太扎实,还需要多看书,和相关的教学视频进行巩固和温习。第三点就是自己的算法的理解和认识都比较少,之后要主动的去了解各类算法,提升代码素养。第四点就是提高代码的规范性和可读性,老师发了有关规范性的阿里巴巴开发手册,还需要之后认真的浏览,并养成良好的代码习惯。并且之后我打算在后续的题目中,多用新的方法去解决问题了,有意识的让代码具有可持续性,可以重复利用。在一定程度上,逐渐对软件工程有了更深刻的理解,我觉得软件工程的核心不在于写代码,而是在于如何设计一个简洁,易懂,易修改,且可持续性的设计方案,减少书写时的BUG。这些就是我对这三次训练集的感悟。