题目要求
分析
这题本身的话,题意就挺烦人,下面分析一下。
本题标签“高性能”,再看看数据范围,暴力匹配必死无疑。我讨厌用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 !!!