字符流中第一个不重复的字符
思路:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符 “go” 时,第一个只出现一次的字符是 “g”。当从该字符流中读出前六个字符“google" 时,第一个只出现一次的字符是 “l”。
这一题思路是比较清晰的,首先我们需要一个数组来记录各个元素出现的频率,还需要用一种数据结构记录各个字符出现的顺序,这个数据结构最合适的无疑是队列,那么代码就好写了:
private int[] cnts = new int[26];
private Queue<Character> queue = new LinkedList<>();
public void Insert(char ch) {
cnts[ch - 'a']++;
queue.add(ch);
while (!queue.isEmpty() && cnts[queue.peek() - 'a'] > 1)
queue.poll();
}
public char FirstAppearingOnce() {
return queue.isEmpty() ? '#' : queue.peek();
}
但是这就有一个问题,题目中并没有说出现的字符一定是小写呀,小小的吐槽一下剑指offer的题目,总是表述不清呀,提供的题例也太少了ε(┬┬﹏┬┬)3但是实际上应该还是怪我没有考虑周密,所以这一题给我最大的教训是,遇到这种字符没有指定大小写的时候,直接使用:
int[] cnts = new int[256];
然后存入字符的时候只需要:
cnts[ch]++;
即可,又方便又不容易出错,希望我下次记住不犯这种低级错误(●ˇ∀ˇ●)
下面给出正确代码:
private int[] cnts = new int[256];
private Queue<Character> queue = new LinkedList<>();
public void Insert(char ch) {
cnts[ch]++;
queue.add(ch);
while (!queue.isEmpty() && cnts[queue.peek()] > 1)
queue.poll();
}
public char FirstAppearingOnce() {
return queue.isEmpty() ? '#' : queue.peek();
}
还可以用LinkedHashMap,可以保存输入的顺序:
//Insert one char from stringstream
Map<Character,Integer> map = new LinkedHashMap<>();
public void Insert(char ch)
{
map.put(ch,map.getOrDefault(ch,0)+1);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Character key = (Character)iter.next();
int val = map.get(key);
if(val>1){
iter.remove();
}else{
return key;
}
}
return '#';
}