#37801: 最後兩題MLE


zhoudaniel02@gmail.com (周孝倫)

學校 : 銘傳大學
編號 : 235507
來源 : [120.125.89.13]
最後登入時間 :
2024-10-04 15:44:35
c508. 去蟲 | From: [223.137.53.228] | 發表日期 : 2023-10-08 23:51

我用的方法是輸入用Bufferedreader,將陣列排序後,toString去掉括號和逗號輸出,然後將陣列去掉重複的,反過來toString去括號逗號輸出

import java.io.*;

import java.util.*;

public class add {

public static void main(String[] args) throws IOException {

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

int n = Integer.parseInt(reader.readLine());

String[] s = reader.readLine().split(" ");

int[] num = new int[n];

for (int i = 0; i < n; i++)

num[i] = Integer.parseInt(s[i]);

Arrays.sort(num);

String line1 = Arrays.toString(num);

line1 = line1.replace("[", "").replace("]", "").replace(",", "");

System.out.println(line1);

String[] words = line1.split(" ");

Set<String> uniqueWords=new LinkedHashSet<>(Arrays.asList(words));

line1 = String.join(" ", uniqueWords);

s=line1.split(" ");

for (int i = 0; i < s.length / 2; i++) {

String k=s[i];

s[i]=s[s.length-i-1];

s[s.length-i-1]=k;

}

line1 = Arrays.toString(s).replace("[", "").replace("]", "").replace(",", "");

System.out.println(line1);

}

}

 

 
#37802: Re: 最後兩題MLE


liaoweichen1024@gmail.com (M_SQRT)

學校 : 新北市立新莊高級中學
編號 : 195452
來源 : [150.117.3.92]
最後登入時間 :
2024-11-21 20:54:31
c508. 去蟲 | From: [118.150.177.13] | 發表日期 : 2023-10-09 01:45

我看到了幾個不建議的寫法:
 
1. split函式
輸入時split函式不建議使用,可以改成用StringTokenizer拆字串,或是直接使用StreamTokenizer輸入浮點數轉整。(兩個名字很像,不要搞混)
 
不建議用split的原因是因為Java的String的設計方式(關鍵字:String Pool),它是基於記憶體安全而有這樣的設計,但缺點是一個10000個字元的字串+1個字,系統將會複製一整份字串,重新建立一個長度10001的,split拆出來的東西絕對不會使用同一段記憶體,所以這個函式在這個位置使用並不適合。
 
2. replace函式
一樣是String Pool的原因,超級傷記憶體。
 
3. Set
已排序的資料,只為了刪掉重複的而放Set實在沒有必要,Set是樹結構,已排序的資料是樹的worst case,雖然Set的會保證樹平衡,但還是做了太多不必要的動作。
 
總結
這題不難,用整數陣列排序,手動刪掉(略過)重複的說不定是最有效率的寫法。
我注意到你似乎很常使用String搭配不同函式處理資料,但這樣的寫法對於解題並不適合,時間不快,還耗記憶體,大的測資一定爆。
 
 
 
已下為推薦解法
 
1. StreamTokenizer輸入,存於int[] num = new int[n];
2. Arrays.sort(num);
3. 順敘遍歷每個元素,存入StringBuilder,最後一次輸出。
4. 反向遍歷每個元素,跳過重複的,存入StringBuilder,最後一次輸出。
 
StringBuilder相當於可以動態調整記憶體的String,其記憶體的使用方式更適合重複修改字串。
 
我直接給你程式碼,反正不會Java的也不知道怎麼抄

StreamTokenizer st = new StreamTokenizer(new java.io.BufferedReader(new java.io.InputStreamReader(System.in)));
st.nextToken();
int N = (int) st.nval;
int[] num = new int[N];
for(int i=0; i<N; i++) {
    st.nextToken();
    num[i] = (int) st.nval;
}

Arrays.sort(num);

StringBuilder ans = new StringBuilder();
for(int i=0; i<N; i++) {
    ans.append(Integer.toString(num[i]));
    ans.append(' ');
}
System.out.println(ans);

ans = new StringBuilder();
int keep = -1;
for(int i=N-1; i>=0; i--) {
    if(num[i] != keep) {
        keep = num[i];
        ans.append(Integer.toString(num[i]));
        ans.append(' ');
    }
}
System.out.println(ans);

 
或著其實這樣的輸出情況用BufferedWriter其實更適合
 

BufferedWriter bw = new BufferedWriter(new java.io.OutputStreamWriter(System.out));
for(int i=0; i<N; i++) {
    bw.append(Integer.toString(num[i]));
    bw.append(' ');
}
bw.append('\n');

int keep = -1;
for(int i=N-1; i>=0; i--) {
    if(num[i] != keep) {
        keep = num[i];
        bw.append(Integer.toString(num[i]));
        bw.append(' ');
    }
}
bw.flush();

 
ZeroJudge Forum