前言
笔者前几天在刷一道牛客网上的华为校招的练习题,被这道练习题(和华为)坑了一把,这几天越想越郁闷,所以记下这次遇到的bug。
题外话
当时的题目如下,感兴趣的同学可以瞧瞧,我写的参考代码会放到最后。
数据表记录包含表索引和数值(int范围的整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
输入描述:
先输入键值对的个数
然后输入成对的index和value值,以空格隔开
输出描述:
输出合并后的键值对(多行)
入正题
当时我想的是先用nextInt()读取到第一个数,读到该数后建立一个for循环,然后再使用nextLine()循环读入下一行的数值,一开始的代码大概如下。
毫无疑问,输入案例后就开始报错了。
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:592)
at java.lang.Integer.parseInt(Integer.java:615)
at com.zp.huaweinowcoder.main8.Main.main(Main.java:17)
说我输入的是空字符串。后来几经查找才查出缘由。
错误原因
第一得知道在控制台输入的数据字符会先进缓冲区中等待Scanner的扫描,除非遇到空格或者回车之类的空白符才会停止扫描。
nextInt() 的原理是扫描到空白符时会把空白符前面的数据读取走,最后再缓冲区遗留空白符——"\r
"。
nextLine() 的原理是把连同空白符在内的一行一同读取。
所以这里就不难理解为什么读完nextInt()后nextLine()再读是一串空字符,另外next(),nextDouble(),nextFloat() 这些与nextInt()同理,所以使用时都得注意空格符。
解决办法 自然就是执行nextInt()后再加个nextLine()把空格符读走。
附上算法代码
import java.util.*;
/**
* @author ZP
* @date 2020/1/12.
*/
public class Main {
public static void main(String[] args) {
Scanner sr = new Scanner(System.in);
while (sr.hasNext()){
int n = sr.nextInt();
sr.nextLine();
Map map = new HashMap();
for (int i = 0; i < n; i++) {
String[] strAnrry = sr.nextLine().split(" ");
if (map.containsKey(Integer.parseInt(strAnrry[0]))) {
int oldn = (int) map.get(Integer.parseInt(strAnrry[0]));
int newn = oldn + Integer.parseInt(strAnrry[1]);
map.replace(Integer.parseInt(strAnrry[0]),newn);
}else {
map.put(Integer.parseInt(strAnrry[0]),Integer.parseInt(strAnrry[1]));
}
}
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); //获取map集合的所有"映射"的Set集合,这里规范每个映射的类型为Map.Entry<K, V>(于Set集合中无序存放)
List<Map.Entry<Integer, Integer>> list = new ArrayList<Map.Entry<Integer, Integer>>(entrySet); //新建List集合获取Set集合的所有元素("映射"对象)(顺序与Set集合一样)
/**
* 接下来的排序是list的专长了
* 通过“比较器(Comparator)”,对list进行排序
*/
Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o1.getKey().toString().compareTo(o2.getKey().toString());
}
});
Iterator<Map.Entry<Integer, Integer>> iter = list.iterator(); //获取List集合的迭代器,Map.Entry<K, V>为迭代元素的类型
while(iter.hasNext()){
Map.Entry<Integer, Integer> item = iter.next();
Integer key = item.getKey();
Integer value = item.getValue();
System.out.println(key + " " + value);
}
}
}
}