超大容量文本的单词统计(洛谷P1308题题解,Java语言描述)
題目要求
P1308題目鏈接
分析
這題本身的話,題意就挺煩人,下面分析一下。
本題標簽“高性能”,再看看數據范圍,暴力匹配必死無疑。我討厭用char[]慢慢墨跡,Java操作這個很煩人,所以我們就爭取用String解決問題吧!!
要做兩件事:一是獲取Pattern單詞在Text的眾多單詞里出現的次數,二是獲取Pattern單詞在Text的眾多單詞里的首次出現位置。
我為什么不說是文本的匹配而說單詞匹配,看下去,你就明白了。
因為如果說匹配字符串也就可以用String類的indexOf()方法,只是沒法直接處理計數,但開個while循環就可以了,也還好辦。
要這樣也就好了,可惜很惡心,并不是。
它是用空白字符分隔文本為N個單詞,我們要匹配單詞而不是全文本匹配,對串的普通解法不能解決問題。
這樣的話我們的直接思維可能是split(),直接分隔" “就行,但不行。
因為,惡心的是,看提示的一則測試數據,WA一次就發現可能只是任意數量空白字符而已……
所以要用正則表達式”\\s+"進行切分。
但是~~這樣的話你交上去只能得30分,其實根本就思路不對,根據獲取的數據集3,統計的應該是從開頭到那里的indexOf,那直接的思維就是說,先做一個indexOf,在慢慢去計數唄,可惜還不對,因為這樣又回到了文本匹配而不是單詞匹配。
真讓人頭禿啊,那繼續琢磨,我們把匹配換成" " + pattern + " ",這樣就可以保證前后是與其他單詞隔開的,即單獨成詞,對不起,還是不行啊,因為忽略了開頭結尾的特判。
這一加上對開頭結尾的考慮,代碼量激增,必須加很多變量去做過程的處理。具體的看最后的AC代碼就行啦,為了調整整個不出Bug,比較麻煩,所以這題讓人惡心。
比如我們要先用startWith(pattern + " “)做開頭的判斷,用endWith(” " + pattern)做結尾的判斷,過程中怎么處理balabala,過程怎么進行躍進式的indexOf計數,如何保證第一次就是真的第一次,也會漏結尾的情況balabala,看代碼就好了,多說無益。
還有那個“超大容量”,看后面我第二次提交的情況吧,那是什么鬼數據啊,我的記事本和Word都快炸了……好在只有測試數據9一個測試用例這樣,不然豈不……太慘了吧……
此題比較惡心,不想多說了。
第一次提交——WA
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String pattern = scanner.nextLine();String[] text_array = scanner.nextLine().split(" ");int counter = 0, index = -1;for (int i = 0; i < text_array.length; i++) {String s = text_array[i];if (s.equalsIgnoreCase(pattern)) {counter++;if (index == -1) {index = i;}}}if (index == -1) {System.out.println(-1);} else {System.out.println(counter + " " + index);}scanner.close();} }錯因前面分析了,就不說了,一看就知道的。
分享一下測試數據3:
in
u
tIXHUguyz PZYAJL BIv NAPoemaJ aTF LOvhV m s LSa n xDn mQnO T ettIq T AL fG B Xme t fct U tQ d
out
1 92
第二次提交——MLE
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String pattern = scanner.nextLine().toUpperCase(), text = scanner.nextLine().toUpperCase();int length = pattern.length(), counter = 0, firstIndex = -1, tempIndex = -1;boolean endFlag = false;if (text.startsWith(pattern + " ")) {counter++;firstIndex = 0;pattern = " " + pattern + " ";tempIndex = text.indexOf(pattern);}if (text.endsWith(" " + pattern)) {counter++;endFlag = true;}pattern = " " + pattern + " ";if (counter == 0) {firstIndex = tempIndex = text.indexOf(pattern);}while (tempIndex != -1) {text = text.substring(tempIndex + length);tempIndex = text.indexOf(pattern);counter++;}if (firstIndex == -1) {if (endFlag) {System.out.println(1 + " " + (text.length()-1));} else {System.out.println(-1);}} else {System.out.println(counter + " " + (firstIndex+1));}scanner.close();} }這個測試數據9……我真沒法Share,太大了,這就是我說的超大容量……
這樣吧,我把文本數據導進了Word,我先進的電腦卡爆了,加載的數據:
當然這在現在的海量文本數據里面微乎其微,但你要知道這只是一個簡單的OJ題啊,這么大的數據量,用Java不得炸裂!!
但我們轉而思考自身可能引發超時超內存的問題:數組!!
我們沒開數組啊??但String本身不就有數組嗎!!!
恍然大悟,我們開了太多substring()了啊,刪去就好,換一個indexOf()的重載方法就好!!!
烏拉烏拉烏拉!!!
第三次提交——AC
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String pattern = scanner.nextLine().toUpperCase(), text = scanner.nextLine().toUpperCase();int length = pattern.length(), counter = 0, firstIndex = -1, tempIndex = -1;boolean endFlag = false;if (text.startsWith(pattern + " ")) {counter++;firstIndex = 0;pattern = " " + pattern + " ";tempIndex = text.indexOf(pattern);}if (text.endsWith(" " + pattern)) {counter++;endFlag = true;}pattern = " " + pattern + " ";if (counter == 0) {firstIndex = tempIndex = text.indexOf(pattern);}while (tempIndex != -1) {tempIndex = text.indexOf(pattern, tempIndex+length);counter++;}if (firstIndex == -1) {if (endFlag) {System.out.println(1 + " " + (text.length()-1));} else {System.out.println(-1);}} else {System.out.println(counter + " " + (firstIndex+1));}scanner.close();} }總結
- 在處理一個問題的時候,其實稍加變換解決思路就能大有改觀。
- 解決問題就是根據已知,不斷轉化轉化再轉化,直到轉化出我們需要的條件,再求解。
- Java的API博大精深,不斷研究,總會有新收獲呢。
不知道大家可有收獲?今年是大年初一,新春快樂@All !!!
總結
以上是生活随笔為你收集整理的超大容量文本的单词统计(洛谷P1308题题解,Java语言描述)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 火柴棒等式(洛谷P1149题题解,Jav
- 下一篇: 单身汪的电梯之旅(洛谷P1897题题解,