Java IO速度和佔用記憶體的極致優化方法,模板方法【從hdu 2602 說起】
談起java,給人的第一映像是什麼?除了簡單方便易上手,跨平臺可移植,各種函式庫支援類應有盡有不用重複造輪子這些特性之外,恐怕就是速度慢,佔用記憶體高了吧。不可否認,java執行速度和記憶體佔用方便確實無法比肩C/C++。隨手舉一個很直觀的栗子,在ACM等其他演算法競賽中,普通給java的程式碼執行的時間往往都是C和C++ 2~~3倍,由此可見一斑。不過我們今天要說的就是,演算法效率一樣的情況下,如何去優化java的速度,讓他在提供編碼方便的同時,速度和記憶體上比肩一般的C和C++。
(/**部落格記錄了小菜尋找優化解法的過程 === 嫌拖拉的同學可以直接拉到最末看總結出的模板 */)
為了方便直觀對執行時間和佔用記憶體有直觀的感受,我們拿 hdu 2602這個題目舉栗子。因為在OJ上能直接給出程式的執行時間和佔用記憶體。
hdu 2602 是一個沒有任何變化的經典01揹包問題,對於01揹包問題,一維的dp做法在演算法上已經到極致不能再優化了(參考dd巨巨的揹包九講)。在大家演算法效率都是一樣的情況下,我們看看速度和記憶體佔用有多大差別。(提交語言都是java的情況下)
最開始我連續提交了好幾次,雖然AC了,但是程式碼執行記憶體開銷始終在1萬3千多k,我繼續往後翻了一下java的提交記錄
大都是在1萬多k 以上,雖然這數字看著有點大,但是既然那麼多人都是這麼大的記憶體佔用,那就應該是java本身的問題了。 ========我繼續往後翻=========可是當我繼續往後翻的時候,就感覺不對了,同樣是java,同樣的演算法,怎麼還能有這麼不可思議,整整少了一個數量級的記憶體佔用,整整快了一倍的速度
快個幾十毫秒,記憶體多個幾十幾百k 還能理解,但是這不是一個幾十幾百k了,這是上萬的差別了,同樣是用java同樣的演算法(應該是),居然出現了上萬的差別。這就讓人不能忍受了。
下面是我自己第一次提交的程式碼,用的是直觀二維的做法。耗時468ms,佔用記憶體24948k
在發現自己記憶體佔用比人家高了那麼多之後,我又換成一維的解法。 耗時546ms,佔用記憶體 13908k。
速度還是不盡人意,我試著直接寫在main 函式裡面,省去函式呼叫看會不會快一點。這次是546ms, 13940k,並沒有多大的變化。甚至還多了一點,我想應該是隨機的吧。
後來喪心病狂的我又嘗試把 i,j 還有陣列的定義都放在迴圈外,然而時間還是微乎其微的變化,嘗試著像以前一樣固定陣列,然和時間也還是沒有變化。於是意識到這不是普通小優化能解決的了。
========================糾結糾結嘗試中====================
由於在hdu 上不能發郵件問別人程式碼怎麼寫的也看不到別人程式碼,只能靠自己一步步的摸索了。百度了好久也沒找到可行的解決方案,最後還是上codeforces看的別人的模板才發現的。
來看一下效果吧,參看cf上排名第二的peter的java程式碼之後, 執行時間降到了234ms,記憶體降到了 9588k
可是9k多k 還是比人家2k多有很大的差距,繼續在 cf上找程式碼嘗試 ======>
這次看的是排名第一的tourist巨巨的程式碼,執行時間降到了 249ms,記憶體佔用降到了7504k,與之前相比整整降低了一倍,下面給出程式碼
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static InputReader in;
static PrintWriter out;
public static void main(String[] args) throws IOException {
in = new InputReader(System.in);
out = new PrintWriter(System.out);
int Case;
Case = in.nextInt();
//int i,j;
// int []v = new int[1010];
// int []w = new int[1010];
// int []m = new int[1010];
while(Case-- > 0){
int n,c;
n = in.nextInt();
c = in.nextInt();
int []v = new int[n];
int []w = new int[n];
int []m = new int[c+1];
for(int i=0;i<n;i++){
v[i] = in.nextInt();
}
for(int i=0;i<n;i++){
w[i] = in.nextInt();
}
Arrays.fill(m,0);
for(int i=0;i<=n-1;i++){
for(int j=c;j>=w[i];j--)
m[j]=Math.max(m[j], m[j-w[i]]+v[i]);
}
System.out.println(m[c]);
}
out.close();
}
static class InputReader {
BufferedReader br;
public InputReader(InputStream stream) {
br = new BufferedReader(new InputStreamReader(stream));
}
public int nextInt() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
int x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public long nextLong() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
long x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public String next() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
StringBuilder sb = new StringBuilder();
while (c > 32) {
sb.append((char) c);
c = br.read();
}
return sb.toString();
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
}
200多的速度和7000多的記憶體和極致的142ms度與2712的記憶體使用相比還有差距,不死心,還想繼續降低下去來著,可是無奈cf上前面兩頁巨巨的java程式碼幾乎都嘗試過了一遍,還是沒能降低下來,那就只好先暫時這樣吧。更加好奇142ms 的極致速度是怎麼出來的,真的堪比C/C++
要是哪位親有程式碼一定要貼出來學習一下啊.......
下面給出IO讀取加速的普遍模板
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
static InputReader in;
static PrintWriter out;
public static void main(String[] args) throws IOException {
in = new InputReader(System.in);
out = new PrintWriter(System.out);
/*
*
* 這裡補充你的實際程式碼 讀取輸入採用 in.nextInt();的形式
*
* */
out.close();
}
static class InputReader {
BufferedReader br;
public InputReader(InputStream stream) {
br = new BufferedReader(new InputStreamReader(stream));
}
public int nextInt() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
int x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public long nextLong() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
long x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public String next() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
StringBuilder sb = new StringBuilder();
while (c > 32) {
sb.append((char) c);
c = br.read();
}
return sb.toString();
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
}
相關推薦
Java IO速度和佔用記憶體的極致優化方法,模板方法【從hdu 2602 說起】
談起java,給人的第一映像是什麼?除了簡單方便易上手,跨平臺可移植,各種函式庫支援類應有盡有不用重複造輪子這些特性之外,恐怕就是速度慢,佔用記憶體高了吧。不可否認,java執行速度和記憶體佔用方便確實無法比肩C/C++。隨手舉一個很直觀的栗子,在ACM等其他演算法競賽中,
JAVA中基本資料型別和佔用記憶體空間大小
byte:1個位元組,8位,-128~127 最大儲存資料量 255short:2個位元組,16位,-32768~32767 最大儲存資料量 65535char:2個位元組,16位,儲存Unicode編碼,用‘’int:4個位元組,32位,負的2的31次方~2的31次方-1
Java IO: InputStreamReader和OutputStreamWriter
作者: Jakob Jenkov 譯者: 李璟([email protected]) 本章節將簡要介紹InputStreamReader和OutputStreamWriter。細心的讀者可能會發現,在之前的文章中,IO中的類要麼以Stream結尾,要麼以Reader或者Writer結
Java IO: Buffered和Data
作者:Jakob Jenkov 譯者: 李璟([email protected]) 本小節會簡要概括Java IO中Buffered和data的輸入輸出流,主要涉及以下4個型別的流:BufferedInputStream,BufferedOutputStream,DataInput
Java IO: FileReader和FileWriter
作者: Jakob Jenkov 譯者: 李璟([email protected]) 本章節將簡要介紹FileReader和FileWriter。與FileInputStream和FileOutputStream類似,FileReader與FileWriter用於處理檔案內容。 F
Java IO: 位元組和字元陣列
原文連結 作者: Jakob Jenkov 譯者: 李璟([email protected]) Java中的位元組和字元陣列,經常被用於臨時儲存應用程式內部的資料,所以陣列也是常見的資料來源以及資料流目的地。如果你在程式執行過程中需要頻繁訪問檔案的內容,你可能會願意將檔案載入到陣列中
Java IO: Reader和Writer
作者: Jakob Jenkov 譯者: 李璟([email protected]) Reader 原文連結 Reader是Java IO中所有Reader的基類。Reader與InputStream類似,不同點在於,Reader基於字元而非基於位元組。換句話說,Reader用於讀取
Java IO: ByteArray和Filter
作者: Jakob Jenkov 譯者: 李璟([email protected]) 本小節會簡要概括Java IO中位元組陣列與過濾器的輸入輸出流,主要涉及以下4個型別的流:ByteArrayInputStream,ByteArrayOutputStream,FilterInput
javax.xml + java.io xml和java物件互轉工具類
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshall
java.io.Reader 和 java.io.InputStream的區別
java.io.Reader 和 java.io.InputStream 組成了 Java 輸入類。Reader 用於讀入16位字元,也就是 Unicode 編碼的字元;而 InputStream 用於讀 入 ASCII 字元和二進位制資料。 在 Java 中,有不同型別的
黑馬程式設計師—JAVA IO(Buffer和Stream)
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS開發</a>、<a href="http://edu.csdn.net"
協助科學家建立機器學習模型 讓進行速度和精準度優化
IBM是一個數據科學應用程式開發工具Watson Studio,添加了一系列人工智慧自動化功能AutoAI,幫助資料科學家解決構建
Java中 Overload和Override的區別。Overloaded的方法是否可以改變返回值的型別?
Overload是過載的意思,Override是覆蓋的意思,也就是重寫。 過載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的引數列表各不相同(即引數個數或型別不同)。 重寫Override表示子類中的方法可以與父類中的某個方法的名稱和引數完全相同,通
android java層直接和kernel互動的最快的方法
http://blog.csdn.net/zengkexu/article/details/8805339 android java 和kernel 的互動方式 按照常規的要通過JNI實現, 然後jni 呼叫HAL的IOCTL ,或者類似Vold 中建立netli
java 中三種常見記憶體溢位錯誤的處理方法
相信有一定Java開發經驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經驗的積累以及對問題根源的探索,終於有了一個比較深入的認識。 在解決java記憶體溢位問題之前,需要對jvm(java虛擬機器)的
eclipse中java,javascrip和html程式碼自動提示功能設定方法和檔案
使用eclipse自帶的外掛,無需另外安裝外掛,具體步驟如下 1.開啟eclipse→Windows→Preferences→Java→Editor→Content Assist 修改Auto Activation triggers for java的值為:zjava 點選apply按鈕
java中Map和List初始化的兩種方法
第一種方法(常用方法): //初始化List List<string> list = new ArrayList</string><string>
java中三種常見記憶體溢位錯誤的處理方法
相信有一定java開發經驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經驗的積累以及對問題根源的探索,終於有了一個比較深入的認識。 在解決java記憶體溢位問題之前,需要對jvm(java虛擬機器
解密:智慧美妝和動效自拍背後的技術【楚才國科】
在如今一個看臉的時代,顏值對大家來說都挺重要。對於女生來說,除了化妝以外還有拍照軟體的美顏技術,相信每個女生的手機上都有至少一個美拍軟體,那麼當中的智慧美妝跟動效自拍的背後運用了怎樣的技術呢? 一般而言,一個完整的人臉識別系統包含三大主要組成部分,即人臉檢測、人臉配准以及人臉識別。三者流水
《瘋狂Java講義(第4版)》-----第3章【資料型別與運算子】
Java的官方API下載 Java語言是一門強型別語言。強型別含義: 所有變數必須先宣告,後使用; 指定型別的變數只能接受型別與之匹配的值 註釋 //單行註釋 /* 多行註釋 */ /** *文件註釋 */ 識別符號 字母、下劃線、美元符號、數字組成。字