用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)
常用的操作:
- 匹配
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");
}
}
宣告:許多程式碼片段,因為參考當時自己在編輯器執行過,後面沒記住網址,如有必要,請聯絡我!