Java写算法题中那些影响你效率的细节(关于暴力破解算法题的细节处理)

QQ讨论群:99979568 多交流才能进步

暂时写到这里,有不懂的欢迎评论, 如果有什么其他提高效率的细节,欢迎评论或者私信我,小编一定努力学习,争取早日分享给大家

如果大家嫌三连累的话,可以看看这个文章,快速三连(●ˇ∀ˇ●)

判断奇数偶数
两个变量的值交换
在使用数组长度的时候需要注意
做OJ或者控制台输入时可以优化的地方
求质数的方法(欧拉筛)
循环中一定不能进行的操作
循环中一定要会的操作(goto语句)
声明变量需要注意的地方
if条件中的boolean应该怎么判断才能提高效率
在使用List,Map,Set时需要注意的事情
long,double类型的正确声明
在数组中最大值和最小值差值比较小的时候,推荐使用的排序





判断奇数偶数

正常情况下,我们都是去对2取模看是不是奇数偶数


package CSDN_Demo;

public class 奇数偶数篇 {
    public static void main(String[] args) {
        int n = 20;
        if(n % 2 == 0) {
            System.out.println("是偶数");
        } else {
            System.out.println("是奇数");
        }

    }
}

 

实际上,位运算的效率会更高

package CSDN_Demo;

public class 奇数偶数篇 {
    public static void main(String[] args) {
        long start1 = System.currentTimeMillis();
        for (int m = 0; m <= 1000; m++) {
            if (m % 2 == 0) {
                System.out.println("是偶数");
            } else {
                System.out.println("是奇数");
            }
        }
        long end1 = System.currentTimeMillis();


        long start2 = System.currentTimeMillis();
        for (int n = 0; n <= 1000; n++) {
            if ((n & 1) == 0) {
                System.out.println("是偶数");
            } else {
                System.out.println("是奇数");
            }
        }
        long end2 = System.currentTimeMillis();

        System.out.println("正常的时间为" + (end1 - start1));
        System.out.println("位运算的时间为" + (end2 - start2));
    }
}

控制台的结果显示如下:
在这里插入图片描述

一个数&1 == 1 证明是奇数 一个数&1 == 0 证明是偶数





两个变量的值交换

当两个变量值需要交换的时候,我们通常情况下是声明一个变量当作中介去交换
其实我们也可以进行位运算,(●ˇ∀ˇ●)

package CSDN_Demo;

public class 两个变量的交换 {
    public static void main(String[] args) {
        int a = 21, b = 35;
        long start1 = System.currentTimeMillis();
        int c;
        for (int m = 0; m <= 1000; m++) {
            a = 21;
            b = 35;
            c = a;
            a = b;
            b = c;
            System.out.println("a:" + a + "b:" + b);
        }
        long end1 = System.currentTimeMillis();


        long start2 = System.currentTimeMillis();
        for (int n = 0; n <= 1000; n++) {
            a = 21;
            b = 35;
            a ^= b;
            b ^= a;
            a ^= b;
            System.out.println("a:" + a + "b:" + b);
        }
        long end2 = System.currentTimeMillis();

        System.out.println("正常的时间为" + (end1 - start1));
        System.out.println("位运算的时间为" + (end2 - start2));
    }
}

结果图如下

在这里插入图片描述
位运算是不是很恐怖 ヽ(*。>Д<)o゜

此时a和b是需要交换的变量

            a ^= b;
            b ^= a;
            a ^= b;

只需要进行这三步操作即可交换变量的值




在使用数组长度的时候需要注意

我们在使用数组长度的时候尽量少使用数组.length
如果真的需要使用的话,我们可以用一个变量去代替数组.length

package CSDN_Demo;

public class 尽量不使用数组的长度 {
    public static void main(String[] args) {
         int[] num = new int[1000];
        long start1 = System.currentTimeMillis();

        for (int m = 0; m < num.length; m++) {
            System.out.println(num.length);
        }
        long end1 = System.currentTimeMillis();


        long start2 = System.currentTimeMillis();
        int len = num.length;
        for (int n = 0; n < len; n++) {
            System.out.println(len);
        }
        long end2 = System.currentTimeMillis();

        System.out.println("使用数组.length的时间为" + (end1 - start1));
        System.out.println("不使用数组.length的时间为" + (end2 - start2));
    }
}

效果图如下:
在这里插入图片描述
效果很明显,不过多解释了(小编是直男癌晚期患者,实在编不下去了,😔,下一个)




做OJ或者控制台输入时可以优化的地方

如果我们接收的是字符串的话,完全可以用IO,效率杠杠滴,不信的话,自己找个OJ测试一下,(不要被效率惊吓到(●ˇ∀ˇ●))
使用IO一定要加上try,catch或者throws标明异常

package CSDN_Demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class String字符串控制台输入 {
    public static void main(String[] args) throws IOException {
        InputStreamReader r=new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(r);
        String s = br.readLine();
        br.close();
        r.close();
        System.out.println(s);
    }
}

如果是字符串需要按照空格分开的话,小编了解有一个StringTokenizer类,可以结合IO很好的使用接收字符串(这里又把IO压缩了一下)

package CSDN_Demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class String字符串控制台输入 {
    public static void main(String[] args) throws IOException {
        //实例化StringTokenizer对象(只传一个参数是按照空格分隔)                              匿名压缩IO接收的
        StringTokenizer stringTokenizer = new StringTokenizer((new BufferedReader(new InputStreamReader(System.in))).readLine());
       //和迭代器一样,判断有没有下一个,有的话就循环输出
        while (stringTokenizer.hasMoreTokens()) {
            System.out.println(stringTokenizer.nextToken());
        }
        
        //这里再提供一下StringTokenizer的另一个构造方法
        //public StringTokenizer(String str,String delim,boolean returnDelims)
        //str - 要解析的字符串。
        //delim - 分隔符。
        //returnDelims - 指示是否将分隔符作为标记返回的标志。

    }
}

如果你接受的int值,我建议还是用Scanner吧,io接收的int是一个数字一个数字接收,并且是按照ASCII的值来接受的

package CSDN_Demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 控制台输入 {
    public static void main(String[] args) throws IOException {
        InputStreamReader r=new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(r);
       int a = br.read();
       int b = br.read();
       //用完了记得关闭(两个都关上最好,提高效率)
       br.close();
       r.close();
        System.out.println(a);
        System.out.println(b);
    }
}

效果图
在这里插入图片描述

Tips:
无论你使用哪种接受方法,输入接收完毕后,最好关闭输入流,提高效率

输入流.close();



求质数的方法(欧拉筛)

小编不过多解释了,自己慢慢缕一缕就懂了

package CSDN_Demo;

import java.util.Arrays;

public class 欧拉筛求质数 {
    public static void main(String[] args) {
        //传入的参数是求n以内的质数
        int[] num = getPrime(1000);
        for (int i : num) {
            System.out.println(i);
        }
    }

    //欧拉筛    不过多解释了,自己慢慢缕一缕
    public static int[] getPrime(int n) {
        int[] list = new int[n + 1];
        int[] prime = new int[n + 1];
        int count = 0;
        for (int i = 2; i <= n; i++) {
            if (list[i] == 0) prime[count++] = i;
            for (int j = 0; j < count && i * prime[j] <= n; j++) {
                list[prime[j] * i] = 1;
            }

        }

        return Arrays.copyOf(prime, count);

    }

}



循环中一定不能进行的操作

这里没有Demo了,在for循环中最好不要声明变量,数组之类的,声明变量或者实例化,一定要放在循环外面,否则会很影响效率的;





循环中一定要会的操作(goto语句)

goto语句在一定程度上是真的好用,Demo也没有举太好的例子,
goto语句:其实就是转移运行的语句

package CSDN_Demo;

public class Goto语句 {
    public static void main(String[] args) {
        //Demo并不是很好,大概举个例子,大家就凑活看一下吧
        //这里求前i项的和>10000时的i
        int sum=0;
        A:
        for (int i = 1; i < 1000; i++) {
            sum =0;
            for (int j = 1; j < i; j++) {
                sum += j;
                if(sum > 10000) {
                    System.out.println(i);
                    break A;
                }
            }
        }
    }
}

可以看,在我写的时候,就直接跳过了A;

在这里插入图片描述

使用goto语句还可以把循环类似递归用,我们也可以continue A;来跳过本次循环



声明变量需要注意的地方

声明变量的时候,最好不要用封装类型,因为在使用的过程中可能因为拆箱解箱导致效率下降
另外正常情况下,封装类型时引用类型,但在Integer中范围在-128~127之中是值类型,需要注意
如果可以用byte就不要用int,如果可以用boolean就不要用byte
遵循用小字节的特点,省内存,其实boolean和byte差不多,Boolean在判断上有优势的



if条件中的boolean应该怎么判断才能提高效率

很多人判断if中的boolean变量还在写
boolean bool = true;
if (bool == true)
其实这里的话,我们用
if (bool) 比较好,如果是取反的话,我们直接用if (!bool)



在使用List,Map,Set时需要注意的事情

List我们经常使用的是:ArrayList和LinkendList
这个ArrayList是数组构成的,所以在遍历的时候会快一些,
LinkendList是链表构成的,所以在增删的时候会快一些
自己结合情况使用,增删多就用LinkendList,遍历多就用ArrayList

Map和Set如果又排序需求的话就用TreeSet或者TreeMap,
如果没有排序需求的话,我建议用HashSet或者HashMap,
Hash在平常情况下使用确实会比其他的快很多



long,double类型的正确声明

我们平常声明long类型的时候,
long temp = 123;
其实这样的话,我们声明的还是int变量
正常的话应该是
long temp = 123L;(其实这里小写的l也行,但是小写的 l 容易和 1 混淆)
double类型也一样
double temp = 123.0D



在数组中最大值和最小值差值比较小的时候,推荐使用的排序

package CSDN_Demo;

public class 差值小的数组排序 {
    public static void main(String[] args) {
        //这里举得例子可能小了点,但这种排序对于数组中最大值和最小值差值小的都比较好用
        int[] num = {1, 2, 3, 5, 2, 1, 4, 5, 6, 8, 1, 2, 3, 5, 4, 9, 7};
        int min = num[0];
        int max = num[0];
        int len = num.length;
        for (int i = 0; i < len; i++) {
            min = Math.min(num[i], min);
            max = Math.max(num[i], max);
        }
        //数组大小为最大值减去最小值
        int[] temp = new int[max - min + 1];
        for (int i = 0; i < len; i++) {
            //使用当前值与最小值的差当作下标
            temp[num[i] - min]++;
        }
        len = max - min + 1;
        for (int i = 0; i < len; i++) {
            while (temp[i] != 0) {
                System.out.print((i + min)+" ");
                temp[i]--;
            }
        }
    }
}

在这里插入图片描述

 

posted @ 2020-05-03 11:42  南墙1  阅读(108)  评论(0编辑  收藏  举报