描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
后台会用以下方式调用Insert 和 FirstAppearingOnce 函数
string caseout = “”;
1.读入测试用例字符串casein
2.如果对应语言有Init()函数的话,执行Init() 函数
3.循环遍历字符串里的每一个字符ch {
Insert(ch);
caseout += FirstAppearingOnce()
}
4.输出caseout,进行比较。
示例
input1: "google"
output1: "ggg#ll"
思路
本题需要需要随时取出字符串流中第一个只出现一次的字符,因此需要记录字符串流中字符的出现顺序以及出现次数,因而需要借助辅助空间,一般可以选择两种办法:
(1)使用LinkedHashMap
记录字符的出现顺序和次数
(2)使用数组记录字符出现的次数(ASCII码表里的字符总共有128个),使用队列记录字符的顺序(出现2次的字符可以直接出队列)
当然,也可以选择HashMap
记录次数,Queue
记录顺序。
1、LinkedHashMap
在本题中,由于在读取字符流时随时都可能调用FirstAppearingOnce()
,因此需要记录字符读取的顺序。使用暴力破解时,一般可以选择LinkedHashMap
来记录单个字符的出现次数。
import java.util.*;
public class Solution {
Map<Character, Integer> map = new LinkedHashMap<>();
//Insert one char from stringstream
public void Insert(char ch)
{
map.put(ch, map.get(ch) == null ? 1 : map.get(ch)+1);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
for(char c : map.keySet()){
if(map.get(c) == 1) return c;
}
return '#';
}
}
2、数组+队列
由于ASCII码表里的字符总共有128个,因此可以直接使用长度128的数组存储字符的出现次数,使用队列来记录字符的出现顺序
import java.util.*;
public class Solution {
Queue<Character> que = new LinkedList<>();
int[] arr = new int[128];
//Insert one char from stringstream
public void Insert(char ch)
{
arr[ch]++;
que.offer(ch);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
//从队列头元素往后遍历,若字符出现的次数大于1次,则直接出队列,否则返回该字符
while(!que.isEmpty()){
if(arr[que.peek()] > 1) que.poll();
else return que.peek();
}
return '#';
}
}