项目场景:
题目编号是387. 字符串中的第一个唯一字符
给定一个字符串 s
,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1
。
问题描述
我的想法是对字符串s的每一个不同字符出现的次数来建立一个HashMap,然后遍历这个HashMap的key,删除出现次数大于1的key值,然后再遍历剩下的key值,比较它们在字符串中的索引大小,返回最小的索引值,不能直接返回第一个出现的key值对应的索引,因为HashMap的key值经过了Hash计算后,不一定就是按照插入顺序进行排序的。具体代码如下:
HashMap<Character,Integer> charMap = new HashMap<>();
for (int i=0; i<s.length(); i++) {
charMap.put(s.charAt(i), charMap.getOrDefault(s.charAt(i),0)+1);
}
for (Character c:charMap.keySet()) {
if (charMap.get(c) > 1) {
charMap.remove(c);
}
}
if (charMap.size() == 0) {
return -1;
}
int minIndex = s.length();
for (Character c:charMap.keySet()) {
minIndex = Math.min(minIndex,s.indexOf(c));
}
return minIndex;
但执行程序时,报下面的错误。
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
at java.util.HashMap$KeyIterator.next(HashMap.java:1461)
at easyQuestion.AAAATempTest.firstUniqChar(AAAATempTest.java:15)
at MainApp.main(MainApp.java:69)
原因分析:
在for循环前面和里面增加一个打印。
System.out.println(charMap);
for (Character c:charMap.keySet()) {
System.out.println(c);
if (charMap.get(c) > 1) {
charMap.remove(c);
}
}
输出如下:
{c=1, t=1, d=1, e=3, l=1, o=1}
c
t
d
e
可以看到每次都是在e之后报错, 那说明问题就是出在e这个字母这了,也就是说e的出现次数大于1,导致HashMap进行remove,导致错误的发生了。看错误报告本身也可以看出是找不到nextNode了。
解决方案:
针对于这个题目的解决方案有一种更简便的方法,就是建立HashMap之后,遍历字符串s,然后直接返回第一个HashMap中值为1的。
public int firstUniqChar(String s) {
HashMap<Character,Integer> charMap = new HashMap<>();
for (int i=0; i<s.length(); i++) {
charMap.put(s.charAt(i), charMap.getOrDefault(s.charAt(i),0)+1);
}
for (int i=0; i<s.length(); i++) {
if (charMap.get(s.charAt(i)) == 1) {
return i;
}
}
return -1;
}
针对于其它问题的解决方案就是,你不能一边循环key值,一边删除元素。可以通过增加一个List进行存储key,不直接删除元素。