1.题目
统计输入英文文章段落中不同单词(单词有大小写之分, 但统计时忽略大小写)各自出现的次数。 输入段落中所含单词的总数不超过100,最长单词的长度不超过20个字母.
输入
一个包含若干句子的段落, 每个句子由若干英文单词组成. 除空格, 逗号和句号外, 这些输入的句子中不含其他非字母字符, 并且, 逗号和句号紧跟在它前面的英文单词后面, 中间没有空格. 段落最后一个字符是回车符, 表示输入结束.
输出
若段落中共有M个不同的英文单词,则按照其在段落中出现的先后顺序输出M行,各行的格式为: 单词中所有字母均用大写形式输出(最长的单词顶格输出,它前面没有多余的空格; 其余单词与其右对齐)+冒号+N个*号+该单词在段落中的出现次数N
样例输入
This is a test. This test is easy. This is a test. This test is easy.
样例输出
THIS:****4
IS:****4
A:**2
TEST:****4
EASY:**2
2.参考
链接: 传送门.
思路:由于知识的匮乏,没能写出来,刚开始想的也是用split函数将字符串分割出来,然后存储到Map集合里面去,最后再输出,看着短短的几个字,却想了好几天。
遇到的问题:
1.用split函数函数分割出来的字符,在这样的时候“ test. This ”,始终分割后会残留一个空格,然后想的是在字符串里面将空格删除,但这是数组嘛,删一个代表会有大量的数据移动,首先这样就是不好的,其次也没写出来(写了下就不想用这个方法了)
2.又打算在Map集合里用remove方法删除,但是自己始终遍历不出空格,用了\t," ",还有ascall码都没遍历出来
3.在从控制台获取数据的时候,只能用nextLine而不能用next,因为对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符next() 不能得到带有空格的字符串。
4.对Map中value值得更新,遍历Map集合,正则表达式等知识点都非常模糊。
5.如果直接遍历Map集合时,它的输出顺序是字典顺序,就与此题不符了,所以网上部分大神还用到了ArrayList集合,但是本篇博客参考的代码利用原字符串数组巧妙的规避了这个问题。
3.思路
然后看了刚才那位大神写的题解之后,发现贼厉害。他最开始是没有用split方法,先用字符串的replace方法,把所有的,.全部替换成空格,再用split方法,传入正则表达式“\s+”,+就表示多个空格,此时刚开始直接split之后的多余空格困扰就解决了。
4.代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class TongJi {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
solution(s);
}
public static void solution(String s) {
Map<String, Integer> m = new HashMap<String, Integer>();
s = s.toUpperCase();// 全部转换成大写字母,便于符合“单词有大小写之分,但统计时忽略大小写”的条件,也可方便最后输出,记得还要重新赋值给s,不然白干,主要还是不太了解这个API
// String[] ss = s.split("[\\s,\\.,\\,]");// 此处需要用到正则表达式,空格,逗号,句号
// 如何用Map遍历输出,
// Integer count = m.get(ss[i]);是之前在韩顺平老师哈夫曼编码的时候学的,如何存储。
//但此处如果直接用HashMap输出,它是按照字典的顺序输出的,所以可以用ArrayList集合
s = s.replace(".", "");
s = s.replace(",", "");
String[] ss = s.split("\\s+");// "+"号表示一个或多个空格
for (int i = 0; i < ss.length; ++i) {
if (ss[i] != null) {
Integer count = m.get(ss[i]);
if (count == null) {// 此时说明Map还没有这个字符数据
m.put(ss[i], 1);// 第一次
} else {
m.put(ss[i], count + 1);
}
}
}
//遍历数组,找出最长的单词长度
int maxLength = ss[0].length();//保存第一个单词的长度
for (int i = 1; i < ss.length; i++) {
if(ss[i].length() > maxLength) {
maxLength = ss[i].length();
}//通过循环找到最长的
}
// 遍历Map集合,但是要经过特殊处理
//1.遍历s数组
for (int i = 0; i < ss.length; ++i) {
int record = 0;
int space = 0;// space清零
for(Map.Entry<String, Integer> entry : m.entrySet()) {
if (entry.getKey() == ss[i] && entry.getValue() != 0) {
record = entry.getValue();
// 打印单词前面的空格
space = maxLength - ss[i].length();
for (int j = 0; j < space; ++j) {
System.out.print(" ");
}
System.out.print(ss[i]);
// 打印:
System.out.print(":");
// 打印**
for (int j = 0; j < record; ++j) {
System.out.print("*");
}
// 打印次数record
System.out.print(record);
// 将已经输出过的字符的value值置为0
m.put(ss[i], 0);
// 换行
System.out.println();
}
}
}
}
}
5.学习心得:
刚开始看别的答案时,用到了输入流,ArrayList集合,还有很多更模糊的知识点。都看不大懂,这篇答案能很好的理解。一会儿再去继续理解消化别的答案。