import java.util.*;
import java.util.stream.IntStream;
/**
* NC277 字符流中第一个不重复的字符
* @author d3y1
*/
public class Solution {
private HashSet<Character> appearSet = new HashSet<>();
private HashSet<Character> firstSet = new HashSet<>();
private HashMap<Character, Integer> map = new HashMap<>();
private Queue<Character> queue = new LinkedList<>();
private HashMap<Character, Integer> linkedMap = new LinkedHashMap<>();
private StringBuilder seq = new StringBuilder();
// ASCII码
private int[] count = new int[128];
// 字符首次出现的位置
private int location = 0;
private int[] array = IntStream.generate(() -> -1).limit(128).toArray();
// 字符出现的位置
int[] index = new int[128];
// 用于标记字符流的位置
int at = 0;
/**
* Insert: Insert one char from string stream
* @param ch
*/
public void Insert(char ch)
{
// Insert1(ch);
// Insert2(ch);
// Insert3(ch);
// Insert4(ch);
// Insert5(ch);
// Insert6(ch);
Insert7(ch);
}
/**
* FirstAppearingOnce: return the first appearance once char in current string stream
* @return
*/
public char FirstAppearingOnce()
{
// return FirstAppearingOnce1();
// return FirstAppearingOnce2();
// return FirstAppearingOnce3();
// return FirstAppearingOnce4();
// return FirstAppearingOnce5();
// return FirstAppearingOnce6();
return FirstAppearingOnce7();
}
/**
* Insert1: HashSet + HashMap + Queue
* @param ch
*/
private void Insert1(char ch){
if(appearSet.contains(ch)){
if(firstSet.contains(ch)){
firstSet.remove(ch);
}
}else{
appearSet.add(ch);
firstSet.add(ch);
queue.offer(ch);
}
map.put(ch, map.getOrDefault(ch, 0)+1);
}
/**
* FirstAppearingOnce1: HashSet + HashMap + Queue
* @return
*/
private char FirstAppearingOnce1(){
if(!firstSet.isEmpty()){
while(!queue.isEmpty() && !firstSet.contains(queue.peek())){
queue.poll();
}
if(!queue.isEmpty()){
return queue.peek();
}
}
return '#';
}
/**
* Insert2: LinkedHashMap => 保证key的先后顺序
* @param ch
*/
private void Insert2(char ch){
linkedMap.put(ch, linkedMap.getOrDefault(ch, 0)+1);
}
/**
* FirstAppearingOnce2: LinkedHashMap => 保证key的先后顺序
* @return
*/
private char FirstAppearingOnce2(){
for(Character ch: linkedMap.keySet()){
if(linkedMap.get(ch) == 1){
return ch;
}
}
return '#';
}
/**
* Insert3: HashMap + StringBuilder
* @param ch
*/
private void Insert3(char ch){
seq.append(ch);
map.put(ch, map.getOrDefault(ch, 0)+1);
}
/**
* FirstAppearingOnce3: HashMap + StringBuilder
* @return
*/
private char FirstAppearingOnce3(){
for(int i = 0; i < seq.length(); i++){
if(map.get(seq.charAt(i)) == 1){
return seq.charAt(i);
}
}
return '#';
}
/**
* Insert4: HashMap + Queue
* @param ch
*/
private void Insert4(char ch){
if(!map.containsKey(ch)){
queue.offer(ch);
}
map.put(ch, map.getOrDefault(ch, 0)+1);
}
/**
* FirstAppearingOnce4: HashMap + Queue
* @return
*/
private char FirstAppearingOnce4(){
while(!queue.isEmpty()){
if(map.get(queue.peek()) == 1){
return queue.peek();
}else{
queue.poll();
}
}
return '#';
}
/**
* Insert5: BitMap + Queue
* @param ch
*/
private void Insert5(char ch){
if(count[ch]++ == 0){
queue.offer(ch);
}else{
queue.remove(ch);
}
}
/**
* FirstAppearingOnce5: BitMap + Queue
* @return
*/
private char FirstAppearingOnce5(){
if(queue.isEmpty()){
return '#';
}
return queue.peek();
}
/**
* Insert6: BitMap + location
* @param ch
*/
private void Insert6(char ch){
// 首次出现
if(array[ch] == -1){
array[ch] = location++;
}else{
array[ch] = -2;
}
}
/**
* FirstAppearingOnce6: BitMap + location
* @return
*/
private char FirstAppearingOnce6(){
int minIndex = Integer.MAX_VALUE;
char ch = '#';
for(int i = 0; i < 128; i++){
if(array[i]>=0 && array[i]<minIndex){
ch = (char) i;
minIndex = array[i];
}
}
return ch;
}
/**
* Insert7: Double BitMap
* @param ch
*/
private void Insert7(char ch){
count[ch]++;
index[ch] = at++;
}
/**
* FirstAppearingOnce7: Double BitMap
* @return
*/
private char FirstAppearingOnce7(){
int minIndex = at;
char ch = '#';
for(int i = 0; i < 128; i++){
if(count[i]==1 && index[i]<minIndex){
ch = (char) i;
minIndex = index[i];
}
}
return ch;
}
}