• 用java以正确的姿势刷CSP


    许多程序算法考试中,用java是个不错的选择,它几乎实现了所有c++能实现的,所以越来越受Acmer的欢迎。总结一下用到的一些技巧和方法。更多关于csp的可参考海岛blog|皮卡丘

    1. 输出

    规格化的输出
    System.out.printf(); // 与C中的printf用法类似.
    System.out.printf(“%d %10.5f ”, 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 空白字符:[ x0Bf ]
    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 非单词边界
    A 输入的开头
    G 上一个匹配的结尾
     输入的结尾,仅用于最后的结束符(如果有的话)
    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就是组的编号)的形式来获取。
            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

    参考博客:http://blog.csdn.net/qq_24486393/article/details/50270481

    //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();
        }  
    }

    全排列,递归

    参考:http://blog.csdn.net/randyjiawenjie/article/details/6313729

    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");
        }
    
    }

    声明:许多代码片段,因为参考当时自己在编辑器运行过,后面没记住网址,如有必要,请联系我!

  • 相关阅读:
    C++ generic tools -- from C++ Standard Library
    18 12 18 给服务器添加logging 日志功能
    18 12 14 python提高 装饰器
    18 12 `12 WSGI 协议
    18 12 07 MySQL 与python 的交互
    转 SQL 的数据库 架构规范 之 58到家数据库30条军规解读
    18 12 06 sql 的 基本语句 查询 条件查询 逻辑运算符 模糊查询 范围查询 排序 聚合函数 分组 分页 连接查询 自关联 子查询
    18 12 4 SQL 的基本 语法
    clion 的 安装 变量配置的 搬运工(有点基础应该能看 大家看不懂 就是我自己看 哈哈哈哈哈哈)
    18 11 27 高级的服务器连接 epoll
  • 原文地址:https://www.cnblogs.com/hulichao/p/9656692.html
Copyright © 2020-2023  润新知