题目描述
- 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
- 地址: 牛客链接
问题分析
- 这题第一眼看到是用HashMap统计每个字符出现的次数,因为考虑到HashMap存储的无序性,value还要存储该字符(key)最后一次出现的位置,然后遍历map,找到出现1次的字符中出现位置最早的那一个。初始想法实在是蠢到家了。
- 首先,可以用LinkedHashMap的存取有序性来做,因为它的底层实现是双向链表,这样先遍历一次,统计次数,然后再遍历一次,找到第一个出现次数为1(value = 1)的字符
- 上面两个方法都是死脑筋!!!用hashmap统计完次数,为什么要用遍历map的方法去找呢,即使hashmap存取具有无序性,但如果按照字符串中字符出现的方式去找,那么自然而然,遇到的第一个出现次数为1的字符即为所求。
- 此外,因为该字符串中只有大小写字母,那么也可以自己定制一个hash表啊,底层是数组。用字符的Asccic码作为hash值,也就是数组的index,这样比hashmap要节省效率。
- 因为Ascii码是 0~255,所以可以定义一个长度256的数组,index为该字符的Asccic码,值为出现次数
- 因为该字符串中只有大小写字母,A-Z对应的ASCII码为65-90,a-z对应的ASCII码值为97-122,所以可以将每个字母的index=int(word)-65,这是一个长度为58的数组,更加节省空间。
经验教训
- 千万别死脑筋!!!
- HashMap的无序性与LinkedHashMap的有序性
- 对于单个字符,可以用数组起到map的效果,字符的Ascii码作为数组的index。
代码实现
public int FirstNotRepeatingChar(String str) {
int length = str.length();
if (str == null || length == 0) {
return -1;
}
if (length == 1) {
return 0;
}
HashMap<Character, CountInfo> map = new HashMap<>();
for (int i = 0; i < length; i++) {
char ch = str.charAt(i);
if (map.containsKey(ch)) {
map.put(ch, new CountInfo(map.get(ch).count + 1 ,i));
}else {
map.put(ch, new CountInfo(1 ,i));
}
}
int resIndex = length;
for (Object o: map.keySet()) {
CountInfo info = map.get(o);
if (info.count == 1) {
resIndex = Math.min(resIndex, info.index);
}
}
return resIndex;
}
public class CountInfo{
int count;
int index;
public CountInfo(int count, int index) {
this.count = count;
this.index = index;
}
public int FirstNotRepeatingChar(String str) {
int length = str.length();
if (str == null || length == 0) {
return -1;
}
if (length == 1) {
return 0;
}
HashMap<Character,Integer> map = new HashMap<>();
for (int i = 0; i < length; i++) {
char ch = str.charAt(i);
if (map.containsKey(ch)) {
map.put(ch, map.get(ch) + 1);
}else {
map.put(ch, 1);
}
}
for (int i = 0; i < length; i++) {
if(map.get(str.charAt(i)) == 1) {
return i;
}
}
return -1;
}
public int FirstNotRepeatingChar(String str) {
int length = str.length();
if (str == null || length == 0) {
return -1;
}
if (length == 1) {
return 0;
}
int[] map = new int[256];
for (int i = 0; i < length; i++) {
map[str.charAt(i)] += 1;
}
for (int i = 0; i < length; i++) {
if (map[str.charAt(i)] == 1) {
return i;
}
}
return -1;
}