# 字符串中的第一个唯一字符(387)
# 题目
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引
。如果不存在,则返回 -1
。
# 示例
s = "leetcode"
返回 0
s = "loveleetcode"
返回 2
# 提示
你可以假定该字符串只包含小写字母
# 算法
# 哈希表 + 遍历
按照{字符:出现次数}
保存map,然后遍历字符串找到第一个值为1
的键
export const firstUniqChar = (s) => {
const map = new Map();
for (const character of s) {
if (map.has(character)) {
map.set(character, map.get(character) + 1);
} else {
map.set(character, 1);
}
}
for (let i = 0; i < s.length; i++) {
if (map.get(s[i]) === 1) {
return i;
}
}
return -1;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 数组 + 遍历
因为都是小写字母,创建一个长度为26的数组,按照字符ascii码-97===数组下标
的规则维护数组
遍历字符串,对应上面创建的字幕出现次数的数组,找到第一个值为1
的字母
export const firstUniqChar = (s) => {
let charArr = new Array(26).fill(0);
for (const character of s) {
charArr[character.charCodeAt() - 97]++;
}
for (let i = 0; i < s.length; i++) {
if (charArr[s[i].charCodeAt() - 97] === 1) {
return i;
}
}
return -1;
};
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 内置方法
出现一次:从前查找索引===从后查找索引
export const firstUniqChar = (s) => {
for (let i = 0; i < s.length; i++) {
if (s.indexOf(s[i]) === s.lastIndexOf(s[i])) {
return i;
}
}
return -1;
};
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# hashMap + 队列
使用Map
来保存字母和其最后出现位置
使用队列queue
来保存没有重复出现的字母且保持相对位置,如果队列头有重复出现的字母我们就推出,最后队列头部就是第一个没有重复的字母,如果队列为空则字符串中没有只出现一次的字母
我们遍历字符串:
- 如果字母在
Map
中没有出现过,那我们在Map
中保存它出现的位置(所以这个值大于等于0),并且以[ch, index]
的形式推入队列queue
- 如果字母在
Map
中出现,那么说明这个字母重复了,我们在Map
中将其值改为-1
(表示重复出现),然后我们检查队列头,如果队列queue
不为空而且队列头部的元素在Map
中标记了位置为-1
(即这个元素重复出现过),那么我们将这个元素推出队列
最后我们检查队列是否为空,如果不为空那么队列头部的元素一定是第一个不重复的字母,我们返回他的位置queue[0][1]
export const firstUniqChar = (s) => {
const queue = [];
const map = new Map();
Array.prototype.forEach.call(s, (ch, i) => {
if (map.has(ch)) {
if (map.get(ch)[1] !== -1) map.set(ch, -1);
while (queue.length && map.get(queue[0][0]) === -1) queue.shift();
} else {
queue.push([ch, i]);
map.set(ch, i);
}
});
return queue.length ? queue[0][1] : -1;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
← 反转字符串(344) 验证回文串(125) →