题目
- 字符串中的第一个唯一字符
给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。
示例 1:
输入: s = “leetcode”
输出: 0
示例 2:
输入: s = “loveleetcode”
输出: 2
示例 3:
输入: s = “aabb”
输出: -1
解法一:使用字符数组存储字符索引
因为题目全是小写字母,这里就可以使用26范围大小的数组来完成字典映射,比如字符a,对应的数组位置为’a’-‘a’ = 0, 数组位置记录原始字符串数字字符出现的首次位置,遍历一次字符串即可确定每个数组索引记录的位置。代码如下:
public int firstUniqChar(String s) {
int[] letters = new int[26];
Arrays.fill(letters, -1);
for (int i = 0; i < s.length(); i++) {
if (letters[s.charAt(i) - 'a'] == -1) {
letters[s.charAt(i) - 'a'] = i;
} else {
letters[s.charAt(i) - 'a'] = -2; // 重复了
}
}
for (int i = 0; i < s.length(); i++) {
if (letters[s.charAt(i) - 'a'] != -2) {
return i;
}
}
return -1;
}
方法2: 使用队列的方式,借助队列先进先出的能力来发现首个不重复的字符串。这里用到了延迟删除的一项能力,即针对某个字符,如果它重复了的话,只要它到对列头部范围内的字符有不重复的就不会直接删除,而是它前面的全部重复了才会删除。举个例子假设队列为
c -> b -> a ->d 当前字符是c,c重复了,但是队列头部d不重复,那么这时候就不删除c,直至下次迭代新的字符时,发现d重复了,才会删除d更新新的不重复的队列头。代码如下:
public int firstUniqChar3(String s) {
int[] letters = new int[26];
Arrays.fill(letters, -1);
Deque<Integer> queue = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
if (letters[s.charAt(i) - 'a'] == -1) {
letters[s.charAt(i) - 'a'] = i;
// 存储的是索引位置
queue.addLast(i);
} else {
letters[s.charAt(i) - 'a'] = -2; // 重复了
// 延迟删除
while (!queue.isEmpty() && letters[s.charAt(queue.peek())-'a'] == -2) {
queue.pop();
}
}
}
return !queue.isEmpty() ? queue.pop() : -1;
}