题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
输入
“google”
返回值
4
哈希法
这是我第一个想到的方法,利用一个哈希表,遍历一次字符串,将字符作为哈希键值,字符的下标作为value,若字符重复出现,则将其value变成10002(最大值);最后遍历一次value的值,返回最小的下标,若最小的下标为10002,则全为重复的字符返回-1
public int FirstNotRepeatingChar(String str) {
HashMap<String, Integer> hashMap = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
String s = String.valueOf(str.charAt(i));
if (!hashMap.containsKey(s)) hashMap.put(s, i);
else hashMap.put(s, 10002); // repeate char
}
int min = 10002;
for (int v : hashMap.values())
if (v < min) min = v;
return min == 10002 ? -1 : min;
}
优化方法
因为字符均为大小写字母a~z
和 A~Z
,其ASCII码分别为97~122
和65~90
,共52个字符,为了方便索引,我们开辟一个58空间的数组,因为122-65+1=58,这样可以通过字符的ASCII码减去65直接得到数组的下标进行操作,数组用来存储每个字符出现的次数,遍历一次字符串记录每个字符出现的次数,最后再遍历一次字符串看哪个字符最先出现的次数为1。这个方法利用了字符的ASCII码,并且使用58空间的数组来记录52个字符出现的次数,用多余的6个空间换取时间,十分灵活巧妙。这种方法也是哈希的思想,但只需要数组来实现即可,因为键值是有限的,所以有时候并不需要总使用哈希表。
public int FirstNotRepeatingChar(String str) {
int count[] = new int[58];
for (int i = 0; i < str.length(); i++)
count[(int) str.charAt(i) - 65]++;
for (int i = 0; i < str.length(); i++)
if (count[(int) str.charAt(i) - 65] == 1)
return i;
return -1;
}