1. 程式人生 > >用java以正確的姿勢刷CSP

用java以正確的姿勢刷CSP

許多程式演算法考試中,用java是個不錯的選擇,它幾乎實現了所有c++能實現的,所以越來越受Acmer的歡迎。總結一下用到的一些技巧和方法。更多關於csp的可參考海島blog|皮卡丘

1. 輸出

規格化的輸出
System.out.printf(); // 與C中的printf用法類似.
System.out.printf(“%d %10.5f\n”, a, b); // 輸入b為字寬為10,右對齊,保留小數點後5位,四捨五入.
// 這裡0指一位數字,#指除0以外的數字(如果是0,則不顯示),四捨五入.

DecimalFormat
DecimalFormat fd = new DecimalFormat("#.00#"
); DecimalFormat gd = new DecimalFormat("0.000"); System.out.println("x =" + fd.format(x)); System.out.println("x =" + gd.format(x));

BigInteger和BigDecimal
包括函式:add, subtract, multiply,divide, mod, compareTo等,其中加減乘除模都要求是BigInteger(BigDecimal)和BigInteger(BigDecimal)之間的運算,所以需要把int(double)型別轉換為BigInteger(BigDecimal),用函式BigInteger.valueOf().
compareTo:根據該數值是小於、等於、或大於 val 返回 -1、0 或 1;
equals:判斷兩數是否相等,也可以用compareTo來代替;
min,max:取兩個數的較小、大者;

BigInteger add(BigInteger other) 
BigInteger subtract(BigInteger other) 
BigInteger multiply(BigInteger other) 
BigInteger divide(BigInteger other) 
BigInteger mod(BigInteger other) 
int compareTo(BigInteger other) 
static BigInteger valueOf(long x)  

輸出大數字時直接使用 System.out.println(a) 即可。

2. 輸入

讀一個字串:String s = cin.next(); 相當於 scanf(“%s”, s); 或 cin >> s;//注意是字串而不是單個字元

3. Arrays.sort() 跟 Collection.sort()

一種是使用Comparable介面:讓待排序物件所在的類實現Comparable介面,並重寫Comparable介面中的compareTo()方法,缺點是隻能按照一種規則排序。
(1)class Person implements Comparable{
(2)//重寫該類的compareTo()方法,使其按照從小到大順序排序

  @Override
    public int compareTo(Person o) {
         return age-o.age;
    }

另一種方式是使用Comparator介面:編寫多個排序方式類實現Comparator介面,並重寫新Comparator介面中的compare()方法,在呼叫Arrays的sort()時將排序類物件作為引數傳入:public static void sort(T[] a,Comparatorc),根據指定比較器產生的順序對指定物件陣列進行排序。陣列中的所有元素都必須是通過指定比較器可相互比較的(也就是說,對於陣列中的任何 e1 和 e2 元素而言,c.compare(e1, e2) 不得丟擲 ClassCastException)。
//建立SortByNumber物件,將其作為引數傳入

Arrays.sort(persons,sortByNumber)方法中

   SortByNumber sortByNumber = new  SortByNumber();
   Arrays.sort(persons,sortByNumber);

//按照學號由低到高排列,建立SortByNumber類,該類實現Comparator,重寫該介面的compare()

class SortByNumber implements Comparator<student>{
    //重寫該介面的compare()使其按照學號由小到大排序(前者減去後者)
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getNumber()-o2.getNumber();    
    }
}

//按照分數由高到低排列,建立SortByScore類,該類實現Comparator,重寫該介面的compare()

class SortByScore implements Comparator<student>{
    //重寫該介面的compare()使其按照分數由高到低排序(後者減去前者)
    @Override
    public int compare(Student o1, Student o2) {
        return o2.getScore()-o1.getScore();
    }

優點是可以按照多種方式排序,你要按照什麼方式排序,就建立一個實現Comparator介面的排序方式類,然後將該排序類的物件傳入到Arrays.sort(待排序物件,該排序方式類的物件)
我喜歡用第二種方法,而且是直接new介面(),z在方法引數中自己實現,當然如果主要的邏輯在排序這裡,用第一種方法其實才是不錯的選擇。

4. Arrays. binarySearch()

注:此法為二分搜尋法,故查詢前需要用sort()方法將陣列排序,如果陣列沒有排序,則結果是不確定的.
substring()方法 是左閉右開的
⑴ .binarySearch(object[ ], object key);
如果key在陣列中,則返回搜尋值的索引;否則返回-1或者”-“(插入點)。插入點是索引鍵將要插入陣列的那一點,即第一個大於該鍵的元素索引。這個插入點是什麼呢,剛開始我也有點困惑,不過當我看了原始碼以後,就明白了,至於為什麼這麼做,(⊙o⊙)…,誰知道?
1.不存在時由1開始計數;
2.存在時由0開始計數。
⑵.binarySearch(object[ ], int fromIndex, int endIndex, object key);
如果要搜尋的元素key在指定的範圍內,則返回搜尋鍵的索引;否則返回-1或者”-“(插入點)。
eg:
1.該搜尋鍵在範圍內,但不在陣列中,由1開始計數;
2.該搜尋鍵在範圍內,且在陣列中,由0開始計數;
3.該搜尋鍵不在範圍內,且小於範圍內元素,由1開始計數;
4.該搜尋鍵不在範圍內,且大於範圍內元素,返回-(endIndex + 1);(特列)
對於這一點,太狠,我記不住。用的大多是找到的,找不到的返回負數來判斷即可。

5. Arrays.fill()

public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
//將指定的 Object 引用分配給指定 Object 陣列指定範圍中的每個元素。填充的範圍從索引 fromIndex(包括)一直到索引 toIndex(不包括)。(如果 fromIndex==toIndex,則填充範圍為空。)
丟擲:
IllegalArgumentException - 如果 fromIndex > toIndex
ArrayIndexOutOfBoundsException - 如果 fromIndex < 0 或 toIndex > a.length
ArrayStoreException - 如果指定值不是可儲存在指定陣列中的執行時型別.
Arrays.fill( a1, value );
a1是一個數組變數,value是一個a1中元素資料型別的值,作用:填充a1陣列中的每個元素都是value

6. 進位制

java中進行二進位制,八進位制,十六進位制,十進位制間進行相互轉換

Integer.toHexString(int i)  //十進位制轉成十六進位制
Integer.toOctalString(int i)  //十進位制轉成八進位制
Integer.toBinaryString(int i) //十進位制轉成二進位制
Integer.valueOf("FFFF",16).toString() //十六進位制轉成十進位制
Integer.valueOf("876",8).toString() //八進位制轉成十進位制
Integer.valueOf("0101",2).toString() //二進位制轉十進位制
String st = Integer.toString(num, base); // 把num當做10進位制的數轉成base進位制的st(base <= 35).

使用cin.toString(2);//將它轉換成2進製表示的字串
還有一種通用的方法。
parseInt(String s, int radix)
至於轉換成二進位制或其他進位制,Java API提供了方便函式,用eclipse 可以檢視到。總結一點,toXXX這種是將十進位制轉換為其他 valueOf 是將其他轉為十進位制。 好像看起來都行嘛,有些是不是有點重複了,我是這麼認為的。
還有一種轉換就是,包裝型與普通的轉換,比如包裝—>普通。To.shortValue().反過來的話用構造方法賦值即可。
- 變數的定義和使用
- 如果是全域性使用的棧,佇列,輸入物件等,儘量定義在全局裡面,因為csp考試是單點測試的,而且可以方便傳參,還有個好處是將空間分配到堆上面,不容易溢位。

 int[] a = new int[100];            //預設用0填充
 Boolean [] b = new Boolean[12];//預設用false填充

8. 正則表示式

Java 中的正則表示式java.util.regex包中,在從母串裡取出子串的題可以用到,方便一些,否則就只能自己判斷了,實屬麻煩,所以總結了一些。參考https://www.cnblogs.com/Mustr/p/6060242.html
(1) 預定義符號介紹

符號 說明
. 任何字元(與行結束符可能匹配也可能不匹配)
\d 數字:[0-9]
\D 非數字: [^0-9]
\s 空白字元:[ \t\n\x0B\f\r]
\S 非空白字元:[^\s]
\w 單詞字元:[a-zA-Z_0-9]
\W 非單詞字元:[^\w]
\ 轉義字元,比如”\”匹配”\” ,”{“匹配”{“。

(2) 數量詞

符號 說明
* 等價於{0,}匹配0至多個在它之前的字元。例如正則表示式“zo*”能匹配“z”以及“zoo”;正則表示式“.*”意味 著能夠匹配任意字串。
+ 等價於{1,}匹配前面的子表示式一次或多次。例如正則表示式9+匹配9、99、999等。
? 等價於{0,1}匹配前面的子表示式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。此元字元還有另外一個用途,就是表示非貪婪模式匹配,後邊將有介紹
{n} 匹配確定的 n 次。例如,“e{2}”不能匹配“bed”中的“d”,但是能匹配“seed”中的兩個“e”。
{n,} 至少匹配n次。例如,“e{2,}”不能匹配“bed”中的“e”,但能匹配“seeeeeeeed”中的所有“e”。
{n,m} 最少匹配 n 次且最多匹配 m 次。“e{1,3}”將匹配“seeeeeeeed”中的前三個“e”。

(3) 邊界匹配符號說明

符號 說明
^ 行的開頭
$ 行的結尾
\b 單詞邊界
\B 非單詞邊界
\A 輸入的開頭
\G 上一個匹配的結尾
\Z 輸入的結尾,僅用於最後的結束符(如果有的話)
\z 輸入的結尾

(4) 其他符號

符號 說明
[]的使用–或 說明
[] 匹配括號中的任何一個字元
[abc] a、b 或 c(簡單類)
[^abc] 任何字元,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,兩頭的字母包括在內(範圍)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](並集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](減去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](減去)

()的使用 – 組
() 將 () 之間括起來的表示式定義為“組”(group),並且將匹配這個表示式的字元儲存到一個臨時區域,這個元字元在字串提取的時候非常有用。捕獲組可以通過從左到右計算其開括號來編號。
(\d) 第一組
((A)(B(C))) 第一組 ((A)(B(C))) 第二組 (A) 第三組(B(C)) 第四組(C)

常用的操作:

  1. 匹配
    String matches()方法。用規則匹配整個字串,只要有一處不符合規則,就匹配結束,返回false。
public static void checkQQ(){
        String qq = "123a45664";
        String regex = "[1-9]\\d{4,14}";
        boolean flag = qq.matches(regex);
        if(flag)
            System.out.println(qq+"...is ok");
        else
            System.out.println(qq+"... 不合法");
    }   
 /*
    匹配
    手機號段只有 13xxx 15xxx 18xxxx
    */
    public static void checkTel()
    {
        String tel = "16900001111";
        String telReg = "1[358]\\d{9}";
        System.out.println(tel.matches(telReg));
    }                       //不合法

2 .切割

public static void splitDemo()
        {

        String str = "avg   bb   geig   glsd   abc";
        String reg = "[ ,]+";//按照多個空格或者逗號來進行切割
        String[] arr = str.split(reg);  
        System.out.println(arr.length);
        for(String s : arr)
        {
            System.out.println(s);
        }
    }  
public static void splitDemo()
        {

        String str = "erkktyqqquizzzzzo";
        String reg ="(.)\\1+";//按照疊詞來進行切割
            //可以將規則封裝成一個組。用()完成。組的出現都有編號。
            //從1開始。 想要使用已有的組可以通過  \n(n就是組的編號)的形式來獲取。
        String[] arr = str.split(reg);  
        System.out.println(arr.length);
        for(String s : arr)
        {
            System.out.println(s);
        }
    }  
     // er,ty,ui,o

3 .替換

 public static void replaceAllDemo()
    {

        String str = "wer1389980000ty1234564uiod234345675f";//將字串中的數字替換成#。

        str = str.replaceAll("\\d{5,}","#");

        System.out.println(str);
   }
        // wer#ty#uio#f
//組選擇
public static void replaceAllDemo()
    {

        String str1 = "erkktyqqquizzzzzo";//將疊詞替換成$.  //將重疊的字元替換成單個字母。zzzz->z

        str = str.replaceAll("(.)\\1+","$1");

        System.out.println(str);
    }
        // erktyquizo

4 . 從某個字串中取某個字串

操作步驟:
    1,將正則表示式封裝成物件。
    2,讓正則物件和要操作的字串相關聯。
    3,關聯後,獲取正則匹配引擎。
    4,通過引擎對符合規則的子串進行操作,比如取出。

public static void getDemo()
    {
        String str = "java shi wo zui xi huan de bian cheng yu yan ";
        System.out.println(str);
        String reg = "\\b[a-z]{3}\\b";//匹配只有三個字母的單詞
        //將規則封裝成物件。
        Pattern p = Pattern.compile(reg);

        //讓正則物件和要作用的字串相關聯。獲取匹配器物件。
        Matcher m  = p.matcher(str);
        //System.out.println(m.matches());//其實String類中的matches方法。用的就是Pattern和Matcher物件來完成的。
        //只不過被String的方法封裝後,用起來較為簡單。但是功能卻單一。
       // boolean b = m.find();//將規則作用到字串上,並進行符合規則的子串查詢。
       // System.out.println(b);
       // System.out.println(m.group());//用於獲取匹配後結果。 
        while(m.find())
        {
            System.out.println(m.group());
            System.out.println(m.start()+"...."+m.end());
                // start()  字元的開始下標(包含)
                //end()  字元的結束下標(不包含)
        }
    }      

9.常用模板

Dfs bfs

//bfs dfs 遞迴跟非遞迴
package com.ccf.test2;
import java.util.LinkedList;  
import java.util.Queue;  
import java.util.Stack;
/**
 * @author   hulichao
 * @date     Dec 1, 2017
 * @version  1.0
 * 
 */

public class Graph {   
    private int number = 9;  
    private boolean[] flag;  
    private String[] vertexs = { "A", "B", "C", "D", "E", "F", "G", "H", "I" };  
    private int[][] edges = {   
            { 0, 1, 0, 0, 0, 1, 1, 0, 0 }, 
            { 1, 0, 1, 0, 0, 0, 1, 0, 1 }, 
            { 0, 1, 0, 1, 0, 0, 0, 0, 1 },  
            { 0, 0, 1, 0, 1, 0, 1, 1, 1 }, 
            { 0, 0, 0, 1, 0, 1, 0, 1, 0 }, 
            { 1, 0, 0, 0, 1, 0, 1, 0, 0 },  
            { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, 
            { 0, 0, 0, 1, 1, 0, 1, 0, 0 }, 
            { 0, 1, 1, 1, 0, 0, 0, 0, 0 }   
            };  

    void DFSTraverse() {  
        flag = new boolean[number];  
        for (int i = 0; i < number; i++) {  
            if (flag[i] == false) {// 當前頂點沒有被訪問  
                DFS(i);  
            }  
        }  
    }  

    void DFS(int i) {  
        flag[i] = true;// 第i個頂點被訪問  
        System.out.print(vertexs[i] + " ");  
        for (int j = 0; j < number; j++) {  
            if (flag[j] == false && edges[i][j] == 1) {  
                DFS(j);  
            }  
        }  
    }  

    void DFS_Map(){
        flag = new boolean[number];
        Stack<Integer> stack =new Stack<Integer>();
        for(int i=0;i<number;i++){
            if(flag[i]==false){
                flag[i]=true;
                System.out.print(vertexs[i]+" ");
                stack.push(i);
            }
            while(!stack.isEmpty()){
                int k = stack.pop();
                for(int j=0;j<number;j++){
                    if(edges[k][j]==1&&flag[j]==false){
                        flag[j]=true;
                        System.out.print(vertexs[j]+" ");
                        stack.push(j);
                        break;
                    }
                }

            }
        }
    }

    void BFS_Map(){
        flag = new boolean[number];
        Queue<Integer> queue = new LinkedList<Integer>();
        for(int i=0;i<number;i++){
            if(flag[i]==false){
                flag[i]=true;
                System.out.print(vertexs[i]+" ");
                queue.add(i);
                while(!queue.isEmpty()){
                    int k=queue.poll();
                    for(int j=0;j<number;j++){
                        if(edges[k][j]==1&&flag[j]==false){
                            flag[j] = true;
                            System.out.print(vertexs[j]+" ");
                            queue.add(j);//注意沒有 break;
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) {  
        Graph graph = new Graph();  
        System.out.println("DFS遞迴:");  
        graph.DFSTraverse();
        System.out.println();
        System.out.println("DFS非遞迴:");  
        graph.DFS_Map();
        System.out.println();  
        System.out.println("BFS非遞迴:");  
        graph.BFS_Map();
    }  
}

全排列,遞迴

package com.ccf.test2;
/**
 * @author   hulichao
 * @date     Dec 1, 2017
 * @version  1.0
 * 
 */
public class RecursionPermutation {

    public static void permutate(String input){
        if(input == null)
            throw new IllegalArgumentException();
        char[] data = input.toCharArray();
        permutate(data, 0);
    }

    public static void permutate(char[] data, int begin){
        int length = data.length;
        if(begin == length)
            System.out.println(data);
        for(int i = begin ; i < length; i++)
        {
            if(isUnique(data, begin, i)){
                swap(data, begin, i);
                permutate(data, begin + 1);
                swap(data, begin, i);
            }                
        }
    }

    private static boolean isUnique(char[] data, int begin, int end){
        for(int i = begin; i < end; i++)
            if(data[i] == data[end])
                return false;
        return true;
    }

    private static void swap(char[] data, int left, int right) {
        char temp = data[left];
        data[left] = data[right];
        data[right] = temp;
    }


    public static void main(String... args){
        RecursionPermutation.permutate("aac");
    }

}

宣告:許多程式碼片段,因為參考當時自己在編輯器執行過,後面沒記住網址,如有必要,請聯絡我!