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]--;
}
}
}
}