题目要求:
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
方法一: 用键值对
1 import java.util.*; 2 public class Solution { 3 public int FirstNotRepeatingChar(String str) { 4 if(str.length()==0) return -1;//这句加不加都能通过所有的测试用例 5 //用HashMap和LinkedHashMap都可以 6 HashMap<Character, Integer> map = new HashMap<Character, Integer>(); 7 //遍历String的每一个字符,将其存入<K,V>键值对中 8 for(int i=0;i<str.length();i++){ 9 if(map.containsKey(str.charAt(i))){ 10 //一开始我还纠结time的初始值怎么没有设置,看14行代码啊 11 int time = map.get(str.charAt(i)); 12 time++; 13 map.put(str.charAt(i),time); //删去11行,将12行改为 ++time也可以 14 }else{ 15 //遇到了新的char,存入新的键值对 16 map.put(str.charAt(i),1); 17 } 18 } 19 for(int j=0;j<str.length();j++){ 20 if(map.get(str.charAt(j))==1) return j; 21 } 22 return -1; 23 } 24 }
hashmap是根据hash值来存储的,而linkedhashmap底层是链表,可以根据顺序存储。比如说输入c,a,hashmap存储计算出c,a的hash值,有可能存成a,c,而linked存储为c,a不会改变输入顺序
不是根据顺序存储,二者都是以hash的形式存储,内部都是hash数组,只不过后者还存储了插入的顺序,使用迭代器迭代的时候应该能反映出来。
人家最后是按照str的顺序遍历的,所以存储时个顺序无关
这题用啥map没啥区别的……因为他最后又在字符串中遍历了一遍。如果非要用到LinkedHashMap的特性的话,可以先遍历LinkedHashMap找到第一个value为1的key,然后str.indexOf(key)就是所求的结果。
都试过了,LinkedHashMap时间复杂度更低一点,
LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。也可以在构造时用带参数,按照应用次数排序。
方法二:数组
链接:https://www.nowcoder.com/questionTerminal/1c82e8cf713b4bbeb2a5b31cf5b0417c
来源:牛客网
说一下解题思路哈,其实主要还是hash,利用每个字母的ASCII码作hash来作为数组的index。首先用一个58长度的数组来存储每个字母出现的次数,为什么是58呢,主要是由于A-Z对应的ASCII码为65-90,a-z对应的ASCII码值为97-122,而每个字母的index=int(word)-65,比如g=103-65=38,而数组中具体记录的内容是该字母出现的次数,最终遍历一遍字符串,找出第一个数组内容为1的字母就可以了,时间复杂度为O(n)
1 链接:https://www.nowcoder.com/questionTerminal/1c82e8cf713b4bbeb2a5b31cf5b0417c 2 来源:牛客网 3 4 public static int solution(String str){ 5 int[] words = new int[58]; 6 for(int i = 0;i<str.length();i++){ 7 words[((int)str.charAt(i))-65] += 1; 8 } 9 for(int i=0;i<str.length();i++){ 10 if(words[((int)str.charAt(i))-65]==1) 11 return i; 12 } 13 return -1; 14 }