问题
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:
s = “abaccdeff”
返回 “b”
s = “”
返回 " "
限制:
0 <= s 的长度 <= 50000
分析
- 使用哈希表(HashMap)来存储
要求的是:字符串中,第一个只出现一次的字符
=>对字符串进行遍历,统计其中的各个字符出现的次数,最后确认第一个只出现一次的字符,即可。
因为统计的时候,对容器的要求:既要确定该字符是什么,又要可以记录该字符出现的次数。并且,该容器的大小是不能确定的,最大为26(因为s只包含小写字母)。
==>想到了用集合来进行存储。
在集合中,list类的,与数组比较相似,不能完全满足要求;set类的也不能满足要求;=>map类的可以满足要求。
采用hashmap来作为容器,统计该字符串中每个元素出现的次数;
(1)时间复杂度:O(n)
=>在第一次扫描时,在哈希表中更新一个字符出现的次数的时间是O(1)。如果字符串的长度为n,那么,第一次扫描的时间复杂度是O(n)。
=>第二次扫描时,同样在O(1)时间内能读出一个字符出现的次数,所以时间复杂度仍是O(n)。
==>总的时间复杂度为:O(n)
(2)空间复杂度:O(1)
使用hashmap,构建起来的辅助数组的大小是一个常数,因此可以认为这种算法的空间复杂度为O(1)
- 使用“有序”哈希表(LinkedHashMap)来存储
要求的是:字符串中,第一个只出现一次的字符
=>仍旧采用集合来存储
==>只不过在存储某个字符(key)的出现次数时,对它的键值的设置处比较巧妙:
如果该字符是第一次出现,则put(item,1);
如果该字符不是第一次出现,则修改他的键值为-1:put(item,-1);
=>因为在第一次遍历string的时候,对于其中的字符(以key来存储)的键值的设置比较巧妙,所以第二趟遍历的时候,可以直接遍历linkedhashmap的对象(理论上可以比直接遍历string要快一点)
采用linkedhashmap的(map接口的)entrySet():返回所有的key-value构成的集合(用Set存储):
其中,出现的第一个:item.value != -1 的item对应的key,
即为:string中第一个只出现一次的字符。
原理:
LinkedHashMap:可以保证在遍历Map元素时,可以按照添加的顺序实现便利------>对于频繁的遍历操作,此类执行效果高于HashMap
1)时间复杂度:O(n)
=>在第一次扫描时,在哈希表中更新一个字符出现的次数的时间是O(1)。如果字符串的长度为n,那么,第一次扫描的时间复杂度是O(n)。
=>第二次扫描时,扫描的是建立起来的LinkedHashMap的对象,理论上会比直接遍历string得到结果的时间短。
==>总的时间复杂度为:O(n)
(2)空间复杂度:O(1)
使用linkedhashmap,构建起来的辅助数组的大小是一个常数,因此可以认为这种算法的空间复杂度为O(1)
- 用一维数组 来实现简单的“哈希表”
实现的思路为:
(1)string为空 的特殊情况
=>如果该string为空,直接return ’ ';
(2)string中包含只出现一次的字符
=>对string进行遍历,在遍历的过程中,对于string中的元素,将该字符对应的map[]中的值,+1;
=>对string进行第二遍遍历,如果某个字符c对应的的map[c-‘a’] == 1,表示该字符只出现了一次,return c;
(3)string中不包含只出现一次的字符
=>如果该string中不包含只出现一次的字符,return ’ ';
1)时间复杂度:O(n)
=>在第一次扫描时,在哈希表中更新一个字符出现的次数的时间是O(1)。如果字符串的长度为n,那么,第一次扫描的时间复杂度是O(n)。
=>第二次扫描时,同样在O(1)的时间内能读出一个字符出现的次数。
==>总的时间复杂度为:O(n)
(2)空间复杂度:O(1)
构建起来的辅助数组的大小是一个常数26*4bit=104bit,因此可以认为这种算法的空间复杂度为O(1)
- 用string类的方法来求解
实现
1、使用哈希表(HashMap)来存储
class Solution {
public char firstUniqChar(String s) {
//定义一个hashmap,来统计字符串中各个字符出现的次数
Map<Character,Integer> map = new HashMap<Character,Integer>();
char resChar = ' ';//因为如果没有 只出现一次的字符,要求返回一个但空格,所以将 一个但空格设置为resChar的初始值
char item;//暂存从string中读取的字符
//遍历字符串s
for(int i=0;i < s.length();i++){
item = s.charAt(i);
//先判断map中是否包含这个item
if(map.containsKey(item)){
//直接将该元素对应的 键值+1
map.put(item,map.get(item)+1);//更新该item对应的键值
} else{
//如果map中不包含这个item
map.put(item, 1);
}
}
//仍旧选择遍历string,[因为hashmap是无序的]
//并且同时,依据string中对应的字符,判断该字符在map中对应的键值(出现次数)的大小,读到第一个键值为1的字符,就返回该字符
for(int i=0;i < s.length();i++){
item = s.charAt(i);
if(map.get(item) == 1){
//该字符对应的键值为1------该字符只出现了一次
resChar = item;//将该字符的值,赋给最终要返回的变量
//这也就意味着,如果没有找到只出现一次的字符,该resChar最终的值,仍旧是' '(返回的是 空格符)
break;
}
}
return resChar;
}
}
2、使用“有序”哈希表(LinkedHashMap)来存储
class Solution {
public char firstUniqChar(String s) {
//定义一个linkedhashmap,来统计字符串中各个字符出现的次数
Map<Character,Integer> map = new LinkedHashMap<>();
char resChar = ' ';//因为如果没有 只出现一次的字符,要求返回一个但空格,所以将 一个但空格设置为resChar的初始值
//遍历字符串s
//暂存从string中读取的字符
char c;
for(int i=0;i < s.length();i++){
c = s.charAt(i);
//先判断map中是否包含这个item
if(map.containsKey(c)){
//直接将该元素对应的 键值+1
map.put(c,-1);//更新该item对应的键值
} else{
//如果map中不包含这个item
map.put(c, 1);
}
}
//因为linkedhashmap是“有序的”----可以按照添加顺序实现遍历,所以可以直接在map中进行查找
//查找第一个value值为1的字符,就是所要求的 第一个只出现一次的字符
//但是,要对linkedhashmap进行遍历的话,需要使用map接口的entrySet()得到一个由所有的key-value对构成的集合(set集合)
for(Map.Entry<Character,Integer> entry : map.entrySet()){
if(entry.getValue() == 1){
resChar = entry.getKey();
break;
}
}
return resChar;
}
}
3、用一维数组 来实现简单的“哈希表”
class Solution {
public char firstUniqChar(String s) {
//string为空的情况
if(s == ""){
return ' ';
}
//string不为空的情况
//用数组来实现 简单的 哈希表
int[] map = new int[26];
char c;//暂存string中的字符
//因为只有小写字母的可能,所以需要的辅助空间为26
//数组元素,可以默认初始化,不用手动置0
//对string的第一遍 遍历
for (int i=0;i<s.length();i++) {
c = s.charAt(i);
//
map[c - 'a']++;
}
//对string的第二遍 遍历
for (int i=0;i<s.length();i++) {
c = s.charAt(i);
if(map[c-'a']==1){
return c;
}
}
//该string中没有:只出现一次的字符
return ' ';
}
}
==>可以用数组,来实现简单的 “哈希表”。
4、用string类的方法来求解
class Solution {
public char firstUniqChar(String s) {
if(s.length() == 0) return ' ';
int index = s.length();
for(char c = 'a'; c <= 'z'; c++) {
int ci = s.indexOf(c);
if(ci >= 0 && ci < index && ci == s.lastIndexOf(c)) {
index = ci;
}
}
return index == s.length() ? ' ' : s.charAt(index);
}
}
换个心情学习,换个状态提升自己!