題目集1-3的總結
前言:總結三次題目集的知識點、題目量、難度等情況
(1)知識點:1、題目01-7-1 if else的使用;2、題目01-7-2 對於輸出格式的控制;3、題目01-7-3 對於輸入格式的控制;4、題目01-7-4 資料型別強制轉換的使用; 5、題目01-7-5 多層if else 的使用;6、題 目01-7-6 對於函式String.charAt(0)的使用;7、題目01-7-7對於資料存在誤差的控制;8、題目01-7-9 從字串中提取內容;9、題目01-7-9從判斷三角形中瞭解對於一些邊界值的測定;10、題目 02-7- 1將字母轉換為數字;11、題目02-7-2 從二進位制資料流中提取有效資料;12、題目02-7-3 String的格式判斷與內容提取;13、題目03-7-1 用類解決一元二次方程;14、題目03-7-2 設計設 置私有屬性,編寫方法;15、題目03-7-03設計聚合類;16題目03-7-4設計聚合類;
題量:題目集1:9題;題目集2:3題;題目集3:4;
難度:題目集1:容易;題目集2:容易;題目集3:中難;
(2)設計與分析:
<1>強制轉換隻需要在資料前面所需要轉換的方式例:a = (float )weight;
輸出的方式與c語言不同,c中使用printf(" ");可以實現將空格插入的內容一同輸出,在JAVA需要使用“+”,輸出所需要的格式
bang=(float) (weight/0.45359237);
yingcun=(float) (high/0.0254);
System.out.println(bang+" "+yingcun);
<2>定義陣列:存在與c語言不同的方式,在c中,使用 int a[10];JAVA中的定義方式存在區別
int num[] = new int [10];
<3>提取字串中的單個字元
在JAVA中可以提取單獨的字元,以下的例子中,定義了一個學生的學號,通過String.charAt(1),就可以提取出第二個字元
String StudentNumber ="18201123";
char a = StudentNumber.charAt(1);
<4>題目字母-數字轉換
題目要求:實現輸入一個由英文字母組成的字串(大小寫均可),將所有英文字母轉換成它們在字母表中的序號,例如:“AbbcD”轉換為“12234”
輸入格式:由英文字母組成的字串(大小寫均可)。例如:“AbbcD”
若包含非英文字母,視為非法輸入。
輸出格式:由英文字母組成的字串(大小寫均可)。例如:“AbbcD”
若包含非英文字母,視為非法輸入。
設計思路:拒絕複雜的思路,將一個個的賦值(使用if將A和a轉變成需要的數字)轉換成使用ASCII表,可以達到按順序實現值的轉換;使用a.length();函式可以測試出字串的長度
踩坑心得:使用in.nextLine()好過於in.next(); in.next無法輸入空格,所以對於非法輸入的判斷的測試點會無法通過
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a,i,j,num;
num=0;
// int num[]=new int[26];
String s = new String();
s = in.nextLine();
a=s.length();
for(i=0;i<a;i++) {
if((s.charAt(i)>='a'&&s.charAt(i)<='z')||(s.charAt(i)>='A'&&s.charAt(i)<='Z')) {
num++;
}
else {
System.out.println("Wrong Format");
break;
}
}
if(i==a) {
for(j=0;j<a;j++) {
if(s.charAt(j)>='a'&&s.charAt(j)<='z') {
num=s.charAt(j)-96;
System.out.print(num);
}
if(s.charAt(j)>='A'&&s.charAt(j)<='Z') {
num=s.charAt(j)-64;
System.out.print(num);
}
}
}
}
}
<5>題目-串列埠字元解析
題目要求:RS232是串列埠常用的通訊協議,在非同步通訊模式下,串列埠可以一次傳送5~8位資料,收發雙方之間沒有資料傳送時線路維持高電平,相當於接收方持續收到資料“1”(稱為空閒位),傳送方有資料傳送時,會在有效資料(5~8位,具體位數由通訊雙方提前設定)前加上1位起始位“0”,在有效資料之後加上1位可選的奇偶校驗位和1位結束位“1”。請編寫程式,模擬串列埠接收處理程式,注:假定有效資料是8位,奇偶校驗位採用奇校驗。
輸入格式:由0、1組成的二進位制資料流。例如:11110111010111111001001101111111011111111101111、
輸出格式:所有英文字母轉換成它們在字母表中的序號,例如:“12234”。
非法輸入輸出"Wrong Format".
設計思路:1:控制字元數量,實現多個字元一組,排除一個一個容錯複雜的判斷,本題需要判斷的資料可以設計成11位為一組
if(a<11)
System.out.println("null data");
else if(a>=11) {//進行正確內容所需要的判斷
}
2:當字串的長度超過11位時,採用迴圈的方式實現每個字元的判斷,首先需要找到0,所在的位置
for(i=0;i<a;i++) {
if(s.charAt(i)=='0'&&a-i<11) {
System.out.println("null data");
break;
}
if(s.charAt(i)=='0'&&a-i>=11)
break;
if(s.charAt(i)!='0'&&i==a-1) {
System.out.println("null data");
break;
}
}
3:在0的後面分部查詢:第一步:計算1的個數(以便最後進行奇偶校驗);第二步:判斷最後的一個是否為1(判斷是否為有效資料);第三步:判斷奇偶校驗;第四步:對於前面最後一位和奇偶校 驗可以進行計數,這樣在最後的一步進行判斷內容是不是為有效資料的時候,存在巨大作用;
踩坑心得:判斷結束符的時候,沒有計數,導致最後判斷不正確
if(s.charAt(j+1)!='1')//結束符號不是1//這裡是錯誤程式碼,沒有計數導致的錯誤
System.out.println("validate error");
if((odd%2==0&&s.charAt(j)=='0'&&s.charAt(j+1)=='1')||odd%2!=0&&s.charAt(j)=='1'&&s.charAt(j+1)=='1'))
System.out.println("parity check error");
if(s.charAt(j+1)!='1')//結束符號不是1{//這裡是正確程式碼
pos++;
System.out.println(pos+":validate error");
}
if((odd%2==0&&s.charAt(j)=='0'&&s.charAt(j+1)=='1')||(odd%2 !=0&&s.charAt(j)=='1'&&s.charAt(j+1)=='1'){
pos++;
System.out.println(pos+":parity check error");
}
但是這並沒有正確,這裡出現了一個難以察覺的問題,對於,所用的開頭沒有重新賦值為0,導致長時間無法正確所以在結尾需要將odd變數重新賦值為0;以下是原始碼,寫的不好僅供瀏覽一下,剛開始還不會使用Debug,所以在裡面用使用了以下輸出一個 i 的值,這樣就達到了當前值檢視(新手使用),但是,推薦去上網查閱以下Debug的使用方法,Debug特別好用,可以一步一步的走,很快的判斷出你的錯誤點
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int a,i,pos=0,j,odd=0; String s = new String(); s=in.nextLine(); a=s.length(); if(a<11) System.out.println("null data"); if(a>=11) { for(i=0;i<a;i++) { if(s.charAt(i)=='0'&&a-i<11) { System.out.println("null data"); break; } if(s.charAt(i)=='0'&&a-i>=11) break; if(s.charAt(i)!='0'&&i==a-1) { System.out.println("null data"); break; } } for(i=0;i<a;i++) { if(s.charAt(i)=='0'&&a-i>=11) { // System.out.print(i); for(j=i+1;j<i+9;j++) {//尋找1的個數 if(s.charAt(j)=='1') odd++; } // System.out.print(j); if((odd%2==0&&s.charAt(j)=='1'&&s.charAt(j+1)=='1')||(odd%2!=0&&s.charAt(j)=='0'&&s.charAt(j+1)=='1')) {//正確的情況 pos++; System.out.print(pos+":"); for(i=i+1;i<j;i++) System.out.print(s.charAt(i)); System.out.printf("\n"); } // System.out.print(i); i=j+1; if(s.charAt(j+1)!='1')//結束符號不是1 { pos++; System.out.println(pos+":validate error"); } if((odd%2==0&&s.charAt(j)=='0'&&s.charAt(j+1)=='1')||(odd%2!=0&&s.charAt(j)=='1'&&s.charAt(j+1)=='1')) { pos++; System.out.println(pos+":parity check error"); } odd=0; } } } } }View Code
<6>String的格式判斷與內容提取
題目要求:學校學生學號格式定義如下:
2位年級號+2位學院號+2位班級號+2位序號,如19041103,
編寫程式處理用全院學生學號連線起來的長字串,學院編號為20,包括17、18、19、20四個年級,請從字串中提取特定兩個班級202017班、202061班同學的學號後四位輸出,輸出編號之間用空格分隔,不換行。
注意:需要排除非法輸入。
輸入格式:院學生學號組成的長字串(學號之間無分隔)
學號格式定義如下:
2位年級號+2位學院號+2位班級號+2位序號,如19041103,
輸出格式:
特定兩個班級202017班、202061班同學的學號後四位
如:1701 6103 1704
設計思路:第一步:對於字元長度的判定,字元長度的界限是8;第二步:尋找需要的學號;以下是原始碼:
View Code踩坑心得:剛開始沒有對格式進行控制,結尾存在空格,需要刪除,改進措施:如果是第一個就先輸出數字,後面每一個都輸出“ +數字”這樣是一個控制輸出格式的方法
if(pos==1)
System.out.print("61"+s.charAt(i+6)+s.charAt(i+7));
else {
System.out.print(" ");
System.out.print("61"+s.charAt(i+6)+s.charAt(i+7));
}
開始的時候,認為迴圈時一組學號一組學號進行的,導致,自己誤以為是i= i+8;導致存在一個錯誤:合法輸入,且其中兩個連續學號錯位組合成一個合乎條件的學號。
,經過更改後,將原來的i = i+8;更改成i= i+1;就可以按照順尋,一個一個的判斷,實現錯位連續學號的排除
<7>題目-7-1 用類解一元二次方程式
題目要求:定義一個代表一元二次方程ax2+bx+c=0的類QuadraticEquation,其屬性為三個係數a、b、c(均為私有屬性),類中定義的方法參考main方法中的程式碼。main方法原始碼:
注意:須提交完整原始碼,包括Main類。
輸入格式:在一行中輸入a、b、c的值,可以用一個或多個空格或回車符分開。
輸出格式:當輸入非法時,輸出“Wrong Format”
當有一個實根時,輸出(2行):
a=值,b=值,c=值:
The root is 值(保留兩位小數)
當有兩個實根時,輸出(2行):
a=值,b=值,c=值:
The roots are 值1 and 值2(均保留兩位小數)
設計思路:使用get和set函式以及構造方法即可;再使用正常的求根公式即可;
踩坑心得:對於公式差不多,只有一些個別的資料沒有改變的,複製貼上的時候,很容造成符號的錯誤,導致隱藏的錯誤難以被發現,推薦,在使用相同的格式的時候注意對個別內容的修改。注意這裡的root1和root2的式公相同,會導致錯誤,所以,需要將內容以下就可以得到正確結果
public double getRoot1() {
root1 = (-b+Math.pow(deita, 0.5))/2*a;
return root1;
}
public double getRoot2() {
root2 = (-b+Math.pow(deita, 0.5))/2*a;//注意這裡的root2和root1的內容相同,導致了錯誤
return root2;
}
以下是正確原始碼:
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input = new Scanner(System.in); double a = Double.parseDouble(input.next()); double b = Double.parseDouble(input.next()); double c = Double.parseDouble(input.next()); //------------------輸入三個值----------- if(a == 0){ System.out.println("Wrong Format"); System.exit(0); } //create a QuadraticEquation object QuadraticEquation equation = new QuadraticEquation(a, b, c);//順便將值傳輸下去 double discriminant = equation.getDiscriminant();//get value of b * b - 4 * a * c //存在返回值 System.out.println("a=" + equation.getA() + ",b=" + equation.getB() + ",c=" + equation.getC()+":"); if (discriminant < 0) { System.out.println("The equation has no roots."); } else if (discriminant == 0) { System.out.println("The root is " + String.format("%.2f", equation.getRoot1())); } else // (discriminant >= 0) { System.out.println("The roots are " + String.format("%.2f", equation.getRoot1()) + " and " + String.format("%.2f", equation.getRoot2())); } } } //有getDiscriminant()-- b * b - 4 * a * c //getB() --返回a,b,c的值 //getRoot1()--返回根的值 getRoot2() class QuadraticEquation{ //your code private double a = 0; private double b = 0; private double c = 0; private double deita = 0; private double root1 = 0; private double root2 = 0; public QuadraticEquation() { super(); // TODO 自動生成的建構函式存根 } public QuadraticEquation(double a, double b, double c) { super(); this.a = a; this.b = b; this.c = c; } public double getA() { return a; } public void setA(double a) { this.a = a; } public double getB() { return b; } public void setB(double b) { this.b = b; } public double getC() { return c; } public void setC(double c) { this.c = c; } public double getDiscriminant() { deita = b * b - 4 * a * c; return deita; } public double getRoot1() { root1 = (-b+Math.pow(deita, 0.5))/2*a; return root1; } public double getRoot2() { root2 = (-b-Math.pow(deita, 0.5))/2*a; return root2; } }View Code
<8> 日期類設計
題目要求:參考題目集二中和日期相關的程式,設計一個類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”格式返回日期值
應用程式共測試三個功能:
求下n天
求前n天
求兩個日期相差的天數
設計思路:第一步:先判斷年月日是否符合要求的範圍,年裡面有月,月裡面有日,迴圈判斷,對於閏年和平年,我們可以單獨建立一個方法,以便在判斷2月的天數的時候,通過判斷是閏年還是平年的方法返回一個boolean型別的值,進行結合判斷即可;第二步:上n天與下n天的計算方法類似(注意對於大資料的考慮,不能僅看一位數或者兩位數的天數,要考慮很大的天數),所以我們通過以年為一組迴圈的方式,最後剩餘的小於366天的時候,進行判斷。第三步:設定換月時要設定的最大天數和最小天數,例如:5月1日的上一天時4月30日,6月1日的上一天時5月31日,對於不同的天數,需要進行設定特殊值需要優先考慮,例如閏年的2月和平年的2月是不一樣的,還有存在跨年的現象,都需要考慮。第四步:設計相差的天數:可以採用引入第三點的方式來計算差值,這樣設計會方便很多
踩坑心得:執行容易超時;當設計為按照每一天來進行判斷當前執行時的天數時,如果資料很大,就會導致執行超時,需要修改演算法;這個屬於優化演算法,非常有必要。對於是否剩餘365天,還是366天,不用管,直接設定最大就可以實現,不用考慮太大
int i,count=0,max=0,newNum,max1=0; newNum=0; if(month==4||month==6||month==9||month==11) max=30; if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) max=31; if(month==2&&isLeapYear(year)==false) max=28; if(month==2&&isLeapYear(year)==true) max=29; if(month==1||month==4||month==6||month==8||month==9||month==11||month==2) max1=31; if(month==5||month==7||month==10||month==12) max1=30; if(month==3&&isLeapYear(year)==false) max1=28; if(month==3&&isLeapYear(year)==true) max1=29; count=1;newNum=n; for(i=0;i<newNum;i++) { day=day+count; if(day>max) { if(month==4||month==6||month==9||month==11) max=30; if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) max=31; if(month==2&&isLeapYear(year)==false) max=28; if(month==2&&isLeapYear(year)==true) max=29; if(month==1||month==4||month==6||month==8||month==9||month==11||month==2) max1=31; if(month==5||month==7||month==10||month==12) max1=30; if(month==3&&isLeapYear(year)==false) max1=28; if(month==3&&isLeapYear(year)==true) max1=29; day=1;month=month+1; if(month==13) { month=1;year=year+1; } }日迴圈
這裡執行一次需要4000ms,僅開啟,就需要很長時間,所以演算法就很複雜,進一步改進:可以提供兩種思路1、直接通過月迴圈就比驕快,也可以通過年迴圈,但是年迴圈需要分別討論再3月前,還是在3月後,這樣的考慮情況會多一點,但是執行的速度就會快很多
for(;n>=366;) { if((isLeapYear(year)==true)&&(month!=2&&day!=29)&&(month<3)) { n = n-366; year = year+1; } else if((isLeapYear(year)==true)&&(month>=3)){ n = n-365; year = year+1; } else if((isLeapYear(year)==true)&&(month==2&&day==29)) { n = n-366; year = year+1; month = 3;day = 1; } else if((isLeapYear(year)==false&&isLeapYear(year+1)==true)&&(month!=2&&day!=28)&&(month<3)) { n = n-365; year = year+1; } else if((isLeapYear(year)==false&&isLeapYear(year+1)==true)&&month>=3) { n = n-366; year = year+1; } else if(isLeapYear(year)==false&&isLeapYear(year+1)==false) { n = n-365; year = year +1; } } if(n<=366) { int i,count=0,max=0,newNum,max1=0; newNum=0; count=1;newNum=n; for(i=0;i<newNum;i++) { if(month==4||month==6||month==9||month==11) max=30; if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) max=31; if(month==2&&isLeapYear(year)==false) max=28; if(month==2&&isLeapYear(year)==true) max=29; day=day+count; if(day>max) { day=1;month=month+1; if(month==13) { month=1;year=year+1; } } } }年迴圈
如果實現了下n天的迴圈,那麼上n天的也可以採用同樣的方法來實現,類推一下就可以。
在這裡我們可以設計一個DateUtil的類,通過在這個類中,設計出多種方法,每種方法都存在不同的get 和set 的方法,就可以返回所需要的值。
<8>日期問題面向物件設計(聚合一)
參考題目7-2的要求,設計如下幾個類:DateUtil、Year、Month、Day,其中年、月、日的取值範圍依然為:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31]、
設計思路:可以從末尾開始設計,先設計年的類,再從年開始到月再到日,返回到DateUtil 返回到main.每一個類中都設有value++ 和value -- ;這樣產生的資料就不會魚龍混雜,結果更加清晰
上一題中的DateUtil是包含了所有的方法,這次設計中,需要將判斷年月日的方法,放在Year類中.判斷日期是否合理的的方法也進行了更改,分別放在了不同的裡面,每一個都單獨進行判斷,各司其職,思路清晰,這是一種面向物件的寫法。
踩坑心得:對於剛接觸Java來說,建立這個類的時候,很多東西還是不明確,在這裡,建立了一個day的類,相當於存在了day中所有的東西,這樣實現環環相扣,大膽去下手,不要出現重複的使用程式碼,直接建構函式實現,這樣既不會導致公式錯誤,也容易檢查出你犯的錯誤
改進建議:對於這個程式來說,其中的耦合度還是很高,他存在了每一環與另外一環相扣的設計,這是不好的,我們需要存在一個控制類將每一個類都控制住,這樣就可以實現單一職責的原則,實現更加低的耦合度
總結:對於以上三次題集,讓我收穫很多,從一開始的對於JAVA的很多語法不熟悉,到現在已經掌握了不少,尤其是字串的應用,學會了很多,基本的定義陣列不同,輸入輸出不同,尤其是同時又printf和println讓我頭暈,對於字串JAVA有很多特別大函式,比如String.charAt(i)可以實現字串中單獨字元的提取,Character.isDigit()可以判斷輸入字串中單獨的一個內容是不是數字,再比如還有Double.valueof函式可以實現將字串中數字轉換成double1型別的數字,substring函式可以將字串中的一部分提取出來,他比charAt(i)強在可以提取多個內容。對於面向物件設計的內容,學習到了一些單一職責的原則,方法的設計與c語言中的函式很像,需要自己揣摩一下,以上便是我從中學到的內容。需要改進的方面,在這段時間的學習中,還有很多語法知識的空白,還需要從實踐中找到,奪取磨練,對於面向物件的設計,現在自己做的還是非常不好,寫的程式碼,還是和以前的c語言的寫法相似,導致程式碼內容不清晰,很拖拉,沒有實現單一職責的原則,需要很多的改進,還有一個很大問題就是程式碼書寫的格式規範程度還是很差,總是亂七八糟的,駝峰命名法,現在有些注意,還有很多的規範書寫沒有寫好,以後需要慢慢加油。對於這幾次題集,雖然最後一次的習題很難,很難受,但是效果還是很好的,慢慢堅持下去,哪怕一開始做的不好,但是經過磨練,會好起來的,加油!