高时空损耗的Scanner会卡爆程序(记洛谷P1567的Java性能优化,Java语言描述)
寫(xiě)在前面
對(duì)性能調(diào)優(yōu),其實(shí)我一個(gè)弱雞,用的也不多,特別是這種OJ連JVM調(diào)優(yōu)都不成。
大佬s勿噴,且看小菜雞如何在一道OJ題里與Java性能搏斗!
題目要求
P1567題目鏈接
簡(jiǎn)單分析
10^9,沒(méi)超int,但是數(shù)值里也必須用int。
10^6,這么大數(shù)組,想坑死我嗎?真狼啊。
這題開(kāi)始沒(méi)注意,后來(lái)發(fā)現(xiàn)卡性能,這么難的情況下還卡那么狠——1s+125MB,這個(gè)對(duì)C/C++還行,對(duì)Java真的不友好,極為不友好!!!
程設(shè)思路簡(jiǎn)潔——逐一比較并由counter記錄即可,counter記錄完與max比較。注意的是學(xué)會(huì)將i在遍歷的時(shí)候進(jìn)行跳躍是對(duì)性能的極大優(yōu)化(雖然本題里這么做沒(méi)啥用~~)
第一次提交——MLE
猝不及防的MLE,人傻了都!!
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int num = scanner.nextInt();int[] array = new int[num];for (int i = 0; i < num; i++) {array[i] = scanner.nextInt();}int max = 0;for (int i = 0; i < num; ) {int counter = 1;int j;for (j = i+1; j < num; j++) {if (array[j-1] < array[j]) {counter++;} else {break;}}i = j;if (max < counter) {max = counter;}}System.out.println(max);scanner.close();} }第二次提交——MLE+WA
這個(gè)寫(xiě)的太沙雕了,無(wú)法形容……我還有臉?lè)懦鰜?lái)~~
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int num = scanner.nextInt();int first = scanner.nextInt();int counter = 1;int max = 0;for (int i = 1; i < num; i++) {int temp = scanner.nextInt();if (first < temp) {counter++;first = temp;} else {if (max < counter) {max = counter;}counter = 1;}}System.out.println(max);scanner.close();} }第三次提交——MLE
這次多跑了一會(huì)兒,看來(lái)是“優(yōu)化”了一點(diǎn)兒~~
在算法上改了改,可惜不行……
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int tem1 = 0, tem2 = 0, counter = 0, max = 0;int num = scanner.nextInt();for(int k = 0; k < num; k++) {tem2 = scanner.nextInt();if (tem2 > tem1)counter++;else{max = (counter > max) ? counter : max;counter = 0;}tem1 = tem2;}System.out.println(max+1);scanner.close();} }第四次提交——TLE
每一次加一個(gè)GC玩玩,超時(shí)了……
確實(shí),GC耗時(shí)啊……
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int tem1 = 0, tem2 = 0, counter = 0, max = 0;int num = scanner.nextInt();for(int k = 0; k < num; k++) {tem2 = scanner.nextInt();if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;System.gc();}System.out.println(max+1);scanner.close();} }第五次提交——TLE
每一萬(wàn)次GC一次,結(jié)果部分通過(guò),部分TLE。
顯然10000次/GC一次,還是頻率太高了:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int tem1 = 0, tem2 = 0, counter = 0, max = 0;int num = scanner.nextInt();for(int k = 0; k < num; k++) {tem2 = scanner.nextInt();if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;if (k % 10000 == 0) {System.gc();}}System.out.println(max+1);scanner.close();} }第六次提交——MLE
干脆開(kāi)到50000次一個(gè)GC,結(jié)果不夠GC就爆掉內(nèi)存了,MLE:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int tem1 = 0, tem2 = 0, counter = 0, max = 0;int num = scanner.nextInt();for(int k = 0; k < num; k++) {tem2 = scanner.nextInt();if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;if (k == 50000) {System.gc();}}System.out.println(max+1);scanner.close();} }第七次提交——TLE
后來(lái)發(fā)現(xiàn)打錯(cuò)了,輸了3000,太沙雕了:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int tem1 = 0, tem2 = 0, counter = 0, max = 0;int num = scanner.nextInt();for(int k = 0; k < num; k++) {tem2 = scanner.nextInt();if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;if (k % 3000 == 0) {System.gc();}}System.out.println(max+1);scanner.close();} }
AC后復(fù)盤,將此處改為每30000次循環(huán)GC一次:
AC后復(fù)盤,將此處改為只在30000處GC一下:
再測(cè)試,30000和70000處分別GC一次:
再測(cè)試,30000和60000分別GC一次:
(這是事后測(cè)的,多次調(diào)參數(shù)都不行,特別是時(shí)空雙爆炸,基本證明這條路走不通~~)
第八次提交——MLE
這是當(dāng)時(shí)測(cè)的,現(xiàn)在看來(lái)就沒(méi)啥意義了~~MLE唄
只不過(guò)將close提前了,可惜沒(méi)用,該爆還得爆~~
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int num = scanner.nextInt();int[] array = new int[num];for (int i = 0; i < num; i++) {array[i] = scanner.nextInt();}scanner.close();int tem1 = array[0], tem2 = 0, counter = 0, max = 0;for(int i = 1; i < num; i++) {tem2 = array[i];if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;}System.out.println(max+1);} }第九次提交——RE→MLE
這個(gè)RE是我智障,忘了加一行nextLine():
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int num = scanner.nextInt();scanner.nextLine();int[] array = new int[num];String str = scanner.nextLine();scanner.close();String[] strings = str.split(" ");for (int i = 0; i < num; i++) {array[i] = Integer.parseInt(strings[i]);}System.gc();int tem1 = array[0], tem2 = 0, counter = 0, max = 0;for(int i = 1; i < num; i++) {tem2 = array[i];if (tem2 > tem1) {counter++;} else {max = Math.max(counter, max);counter = 0;}tem1 = tem2;}System.out.println(max+1);} }在第七行插入: scanner.nextLine(); :
還是不行哇!!
……無(wú)數(shù)次失敗,看來(lái)性能瓶頸真的來(lái)了,可我不甘心……
但是我逐漸冷靜下來(lái),思考著之前的種種策略。
GC不是辦法,因?yàn)镚C會(huì)帶來(lái)大量的性能損耗(主要是時(shí)間,導(dǎo)致了TLE;要是時(shí)間不爆表,空間肯定回收不夠……)
之前有的算法雖然不見(jiàn)得那么好,但我用C能過(guò),Java不能過(guò),顯然問(wèn)題在Java身上。
Java做這個(gè)題確實(shí)折磨一些,但我們正應(yīng)該借此琢磨琢磨孰優(yōu)孰劣呢。
開(kāi)辟的數(shù)組雖然大,但也不至于爆掉125MB內(nèi)存,而且C都能活下來(lái),可見(jiàn)問(wèn)題不在這里,就算你開(kāi)大數(shù)組也未必直接爆炸,這可只有10W啊,也不至于100W啥的,那些太大的可能malloc不來(lái)……
我懷疑問(wèn)題在Scanner身上,查了查性能調(diào)優(yōu)的資料,覺(jué)得這東西很煩人,應(yīng)該是我性能的最大瓶頸~~就拿他開(kāi)刀!!!
最終提交——柳暗花明又AC
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;public class Main {public static void main(String[] args) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));int num = reader.read();reader.readLine();String[] arr = reader.readLine().split(" ");int counter = 0;int max = 0;for (int i = 1; i < arr.length; i++) {int tem1 = Integer.parseInt(arr[i]);int tem2 = Integer.parseInt(arr[i-1]);if((tem1 - tem2) > 0) {counter++;} else {max=Math.max(max, counter);counter = 0;}}System.out.println(max+1);} }弱者落淚~~
敗者食塵~~
但還是給自己點(diǎn)掌聲!!!So——
總結(jié)
以上是生活随笔為你收集整理的高时空损耗的Scanner会卡爆程序(记洛谷P1567的Java性能优化,Java语言描述)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 轻松理解Spring框架的基本思想
- 下一篇: 快速排序+统计→奶牛的耳语(洛谷P129