前言:
前三次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。這些就是我對這三次訓練集的感悟。