最近在拿着《算法筆記》刷PAT的一些題目,準備使用JAVA考一次CSP,發現因爲算法題JAVA選手不太多,網上很少有針對JAVA選手的指南,於是把這幾天查到的、學到的一些技巧整理出來
第一次刷題,學藝不精,我的文章有任何問題或者大家有其他經驗技巧的話,很希望能得到大家的指導
這篇文章會隨着我的學習一點一點更新完善,有同爲JAVA選手的話歡迎大家一起交流
我也寫了一些針對於JAVA實現的、我認爲能學到些東西的題目,由於PAT沒有放寬對JAVA的標準,所以有很多題目時間超限不能AC
我認爲算法主要是練習自己的思維能力,學會方法才最重要,所以我對於那些JAVA超時的題目沒有花大把時間去優化它們,只求通過可通過測試點
JAVA選手刷題須知1
-
首先確保沒有加package,類名稱爲Main。
-
爲了運行效率,請使用
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
- 因爲PAT系統對scanner支持不友好且運行時間長。
-
PAT是單點測試,就是每個測試點只有一組輸入
-
codeup則是多點測試,處理輸入需要使用while()
-
請在使用完bufferedreader之後立刻使用close();方法關閉,否則可能會發生內存泄漏(關閉的越早越好)。
-
【重要】請不要隨便import沒有用到的包,親測PAT若是導入了java.util.Scanner可是你沒有用到scanner,就會返回非零。
-
一般對於100ms時間限制的題目,基本ac不了,哪怕優化得再好。因爲很多乙級題目運行時長(該死的JVM啓動)在100ms上下,運氣好AC的多,運氣差全超時!
-
200ms以上的題目,若是運行超時,那就請不要用暴力破解。
-
還是超時的話,建議換語言。官方說明:選擇合適的語言也是一種技巧,所以不給你JAVA放寬時間限制
代碼技巧
一、JAVA使用
1 數學處理
-
Math.round()四捨五入
功能四捨五入,注意返回值:int(float)、float(double),int/2.0默認double -
兩int相加考慮是否超限,超限使用Long承接
如果兩個int相加會超過範圍,必須使用Long(C的longlong)**
-
JAVA的int範圍是-231——231-1,即-2147483648——2147483647,比C語言的int範圍大的多
-
字符串轉數字,如果初始是空串,注意最後判斷是空串,把空串轉化爲零
String i = ""; int s = 10; while(s-->0){ i+="6"; } // 記得處理空串 if(i.equals("")) i = 0; res = Long.parseLong(i) + 10;
-
任何進制字符串 轉 int
int i = Integer.parseInt("E8", 16); //十六字符串轉int,16代表前的的是十六進制數值
-
int 轉 16進制字符串
String s = Integer.toHexString(i); //int轉十六進制字符串
-
大數字符串轉換爲表示科學計數法
import java.math.BigDecimal; BigDecimal s = new BigDecimal(str);
-
for(char i:charArr)中對i做修改不影響數組中的數據
-
將char[]轉化成String需要使用String.valueOf
不能用
.toString()
,這轉換出來的是地址 -
作爲參數傳入函數的變量,如果函數中調用了變量的修改自身的方法纔會對本身發生變化
public static void main(String[] args) { StringBuilder sb = new StringBuilder("Hello World"); String st = "Hello World" method(sb, st); } public static void method(StringBuilder stringBuilder, String s) { // sb發生了變化,因爲“函數中調用了變量的修改自身的方法纔會對本身發生變化” stringBuilder.append("!") // st不變,他沒有調用能修改自身的方法 st += "!"; }
2 IO、字符、字符串處理
- 字符串相等別用==用
字符串.equals
字符串==比較的是內存地址,equal比較的是值 - Scanner的next()是以空格爲終止的
- 比較器的使用:比較時間字符串
Employee[] emp = new Employee[100]; Arrays.sort(emp, new EComparator()); class Employee { String name; String intime; } class EComparator implements Comparator<Employee> { public int compare(Employee o1, Employee o2) { return o1.intime.compareTo(o2.intime); } }
- JAVA有像C語言一樣的輸出
System.out.printf()
,可用於控制輸出格式,用法與C語言的printf
基本相同System.out.printf("%02d, 2);
- 字符串以“.”分割需要雙斜槓:
String.split("\\.")
- 0比‘0’的ASCII小48
3 其他使用
-
數組轉化爲List:Arrays.asList(數組),返回值爲List類型
-
ArrayList轉化爲數組:ArrayList.toArray(承接數組)
-
數組排序Arrays.sort(類的數組),List排序 Collections.sort(List<類>); 被排序的類類必須實現Comparable接口。默認爲升序
-
數組相等Arrays.euqals(數組1,數組2)
-
int數組默認值0,引用類型數組默認值null
-
迭代Map2
//第一種:普遍使用,二次取值 System.out.println("通過Map.keySet遍歷key和value:"); for (String key : map.keySet()) { System.out.println("key= "+ key + " and value= " + map.get(key)); } //第二種 System.out.println("通過Map.entrySet使用iterator遍歷key和value:"); Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第三種:推薦,尤其是容量大時 System.out.println("通過Map.entrySet遍歷key和value"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第四種 System.out.println("通過Map.values()遍歷所有的value,但不能遍歷key"); for (String v : map.values()) { System.out.println("value= " + v); }
二、簡潔代碼
- 使用while替換for更簡潔
int i = 10; while(i-- > 0){}
- 將大數的每一位存入數組
// n是待存儲的數 num是第幾位 while(n != 0){ ans[num] = n % 10; num++; n /= 10; }
- 輸出數組中每個數字,用空格隔開,最後一個數後無空格
public static void dfs(int n){ if(n / 10 == 0){ System.out.printf("%s", n % 10); return; } dfs(n / 10); System.out.printf(" %s", n % 10); }
三、經驗技巧
-
將秒轉化爲
hh:MM:ss
的格式System.out.println( String.format("%02d",maxWaitTime/3600) + ":" + // 時 String.format("%02d",maxWaitTime%3600/60) + ":" + // 分 String.format("%02d",maxWaitTime%100) // 秒 );
-
compareTo
比較時間字符串(hh:MM:ss)Employee[] emp = new Employee[100]; Arrays.sort(emp); class Employee implements Comparable{ String name; String intime; @Override public int compareTo(Object o) { Employee otherEmplyee = (Employee)o; // -1:this屬性小於other屬性 // 0:等於 // 1:大於 return o1.intime.compareTo(o2.intime); } }
-
“1 10 10 1”是迴文, “110101”不是迴文
-
進位公式
// carry爲進位 mod爲進制 // 加法公式 c[i] = (a[i] + b[i] + carry) % mod; // 進位公式 carry = (a[i] + b[i] + carry) / mod;
-
如果記不住字符
'0'
的ASCII、想要數字字符的ASCII,可以'0'+數字
-
將兩個大數的每一位裝進兩個int數組,通過數組對兩個數進行運算時要將兩長度統一,短的那個數組加長,加長這部分爲0
不同長度A,B進行運算,補零有以下好處- 如果需要reverse可以同時reverse,思路清晰
- 當一個短一個長時,不會忘記輸出長的剩下的那部分
-
大數格式化(三個數一個逗號:100,000,000)
if(sum >= 1000000) System.out.printf("%d,%03d,%03d", sum/1000000, sum%1000000/1000; sum % 1000); else if(sum >= 1000) System.out.printf("%d,%03d", sum/1000, sum%1000); else System.out.printf("%d",sum);
-
分數按大小排序後排名,同分同位
- 同分同位:即下一個分數不連續:如五人排名1 2 2 4 5)
- 如果當前分數不等於上一分數,排名=數組下標+1,否則排名與上一人相同,一般將排名放在排名者的類中
-
按照分數大小排序,分數相同按照姓名字典序排序
public int compareTo(Object o) { Student othStu = (Student)o; if(this.grade < othStu.grade) return -1; else if(this.grade > othStu.grade) return 1; else return this.name.compareTo(othStu.name); } ```
-
升序:12345 ABCD……abcde……
-
降序排序
- Arrays.sort(數組,Collections.reverseOrder());
- 實現
Comparator
接口比較器實現降序:返回o1屬性-o2的屬性
的值public int compare(Student o1, Student o2) { return o1.grade - o2.grade; };
-
二分法:也可以對 有序的 時間字符串數組 使用二分法
//二分查找算法 //特點:查找速度快。要求:數列必須有序 public static int binarySearch(int[] nums,int key){ int start=0; int end=nums.length-1; int mid=-1; while(start<=end){ mid=(start+end)/2; if(nums[mid]==key){ return mid; }else if(nums[mid]<key){ start=mid+1; }else if(nums[mid]>key){ end=mid-1; } } return -1; }
-
計算時間間隔:時間一 不斷自增一秒(分|時|天……) 到時間二
-
這一方法的優點在於,時間自增過程中可以加入其他運算
-
例如:計算從時間一開始打電話到時間二 的電話費用,由於每個小時的費用標準都不一樣,所以可以每自增一分鐘就就這一分鐘的費用,加到總時間裏(PAT甲級 1016 Phone Bills (25分))
while(!Arrays.equals(time1, time2)) { // time1前進一分鐘; time1.min++; // 總消耗時間+1 totalTime++; // 總消耗 = 當前小時一分鐘的價錢(toll) spand += toll[time.hour]; // 分鐘滿60 進位1小時 if(time1.min == 60) { time.min = 0; time1.hour++; } // 小時滿24 進位1天 if(time1.hour == 24) { time1.hour = 0; time1.day++; } }
-
-
字符串轉數字,如果初始是空串,注意最後判斷是空串,把空串轉化爲零
String i = ""; int s = 10; while(s-->0){ i+="6"; } // 記得處理空串 if(i.equals("")) i = 0; res = Long.parseLong(i) + 10;