刷題:一個新JAVA選手學到的技巧

最近在拿着《算法筆記》刷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 數學處理

  1. Math.round()四捨五入
    功能四捨五入,注意返回值:int(float)、float(double),int/2.0默認double

  2. 兩int相加考慮是否超限,超限使用Long承接

     如果兩個int相加會超過範圍,必須使用Long(C的longlong)**
    
  3. JAVA的int範圍是-231——231-1,即-2147483648——2147483647,比C語言的int範圍大的多

  4. 字符串轉數字,如果初始是空串,注意最後判斷是空串,把空串轉化爲零

    String i = "";
    int s = 10;
    while(s-->0){
    	i+="6";
    }
    // 記得處理空串
    if(i.equals("")) i = 0;
    res = Long.parseLong(i) + 10;
    
  5. 任何進制字符串 轉 int

    int i = Integer.parseInt("E8", 16); //十六字符串轉int,16代表前的的是十六進制數值
    
  6. int 轉 16進制字符串

    String s = Integer.toHexString(i); //int轉十六進制字符串
    
  7. 大數字符串轉換爲表示科學計數法

    import java.math.BigDecimal;
    BigDecimal s =  new BigDecimal(str);
    
  8. for(char i:charArr)中對i做修改不影響數組中的數據

  9. 將char[]轉化成String需要使用String.valueOf

    不能用.toString(),這轉換出來的是地址

  10. 作爲參數傳入函數的變量,如果函數中調用了變量的修改自身的方法纔會對本身發生變化

    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、字符、字符串處理

  1. 字符串相等別用==用字符串.equals
    字符串==比較的是內存地址,equal比較的是值
  2. Scanner的next()是以空格爲終止的
  3. 比較器的使用:比較時間字符串
    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);
        }
    }
    
  4. JAVA有像C語言一樣的輸出System.out.printf(),可用於控制輸出格式,用法與C語言的printf基本相同
    System.out.printf("%02d, 2);
    
  5. 字符串以“.”分割需要雙斜槓:String.split("\\.")
  6. 0比‘0’的ASCII小48

3 其他使用

  1. 數組轉化爲List:Arrays.asList(數組),返回值爲List類型

  2. ArrayList轉化爲數組:ArrayList.toArray(承接數組)

  3. 數組排序Arrays.sort(類的數組),List排序 Collections.sort(List<類>); 被排序的類類必須實現Comparable接口。默認爲升序

  4. 數組相等Arrays.euqals(數組1,數組2)

  5. int數組默認值0,引用類型數組默認值null

  6. 迭代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);
      }
    

二、簡潔代碼

  1. 使用while替換for更簡潔
    int i = 10;
    while(i-- > 0){}
    
  2. 將大數的每一位存入數組
    // n是待存儲的數 num是第幾位
    while(n != 0){
        ans[num] = n % 10;
        num++;
        n /= 10;
    }
    
  3. 輸出數組中每個數字,用空格隔開,最後一個數後無空格
    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);
    }
    

三、經驗技巧

  1. 將秒轉化爲hh:MM:ss的格式

    System.out.println(
        String.format("%02d",maxWaitTime/3600) + ":" + // 時
        String.format("%02d",maxWaitTime%3600/60) + ":" +  // 分
        String.format("%02d",maxWaitTime%100) // 秒
    );
    
  2. 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);
        }
    }
    
  3. “1 10 10 1”是迴文, “110101”不是迴文

  4. 進位公式

    // carry爲進位 mod爲進制
    // 加法公式
    c[i] = (a[i] + b[i] + carry) % mod;
    // 進位公式
    carry = (a[i] + b[i] + carry) / mod;
    
  5. 如果記不住字符'0'的ASCII、想要數字字符的ASCII,可以'0'+數字

  6. 將兩個大數的每一位裝進兩個int數組,通過數組對兩個數進行運算時要將兩長度統一,短的那個數組加長,加長這部分爲0
    不同長度A,B進行運算,補零有以下好處

    • 如果需要reverse可以同時reverse,思路清晰
    • 當一個短一個長時,不會忘記輸出長的剩下的那部分
  7. 大數格式化(三個數一個逗號: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);
    
  8. 分數按大小排序後排名,同分同位

    • 同分同位:即下一個分數不連續:如五人排名1 2 2 4 5)
    • 如果當前分數不等於上一分數,排名=數組下標+1,否則排名與上一人相同,一般將排名放在排名者的類中
  9. 按照分數大小排序,分數相同按照姓名字典序排序

    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);
       }
       ```
    
  10. 升序:12345 ABCD……abcde……

  11. 降序排序

    • Arrays.sort(數組,Collections.reverseOrder());
    • 實現Comparator接口比較器實現降序:返回o1屬性-o2的屬性的值
      public int compare(Student o1, Student o2) {
      	return o1.grade - o2.grade;
      };
      
  12. 二分法:也可以對 有序的 時間字符串數組 使用二分法

    //二分查找算法 
    //特點:查找速度快。要求:數列必須有序
    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;
    }
    
  13. 計算時間間隔:時間一 不斷自增一秒(分|時|天……) 到時間二

    • 這一方法的優點在於,時間自增過程中可以加入其他運算

    • 例如:計算從時間一開始打電話到時間二 的電話費用,由於每個小時的費用標準都不一樣,所以可以每自增一分鐘就就這一分鐘的費用,加到總時間裏(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++;
          }
      }
      
  14. 字符串轉數字,如果初始是空串,注意最後判斷是空串,把空串轉化爲零

    String i = "";
    int s = 10;
    while(s-->0){
    	i+="6";
    }
    // 記得處理空串
    if(i.equals("")) i = 0;
    res = Long.parseLong(i) + 10;
    

  1. 參考:https://blog.csdn.net/youyuge34/article/details/60143721 ↩︎

  2. 參考:https://blog.csdn.net/kyi_zhu123/article/details/52769469 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章