剑指offer 50.2 字符流中第一个只出现一次的字符
请实现一个函数用来找出字符流中第一个只出现一次的字符。
例如,当从字符流中只读出前两个字符 go
时,第一个只出现一次的字符是 g
。
当从该字符流中读出前六个字符 google
时,第一个只出现一次的字符是 l
。
如果当前字符流没有存在出现一次的字符,返回 #
字符。
样例
输入:“google”
输出:“ggg#ll”
解释: 每当字符流读入一个字符,就进行一次判断并输出当前的第一个只出现一次的字符。
解题思路
我们可以用一个Map
记录每个字符出现了多少次了,用一个Queue
存从数据流中进来的字符,但需要不断更新Queue
,使得队首的元素是数据流中第一个目前只出现一次的。
插入的操作很简单。直接将字符计数加1
,同时也将字符加入队尾。
注:
题目的含义就是每次调用insert
方法后,会紧跟着调用一次firstAppearingOnce
方法。
由于我们人为规定(维护)了队首元素是数据流中第一个目前只出现一次的字符,所以每次新插入一个元素后,我们先看现在队首元素是否还满足是数据流中第一个目前只出现一次的字符?
- 满足,直接返回它。它确实还是数据流中第一个目前只出现一次的字符
- 不满足,队头一直弹出元素,直到队首的元素重新满足是数据流中第一个目前只出现一次的字符为止,然后判断队列是否为空了
- 为空,返回`‘#’`
- 不为空,返回队首元素
Java代码
class Solution {
Map<Character,Integer> map = new HashMap<>();
Queue<Character> queue = new LinkedList<>();
//Insert one char from stringstream
public void insert(char ch){
map.merge(ch,1,Integer::sum);
queue.offer(ch);
}
//return the first appearence once char in current stringstream
public char firstAppearingOnce(){
if(!queue.isEmpty() && map.get(queue.peek()) == 1) return queue.peek();
while(!queue.isEmpty() && map.get(queue.peek()) > 1){
queue.poll();
}
return !queue.isEmpty()? queue.peek():'#';
}
}