首页 > 试题广场 >

字符流中第一个不重复的字符

[编程题]字符流中第一个不重复的字符
  • 热度指数:322464 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符 "go" 时,第一个只出现一次的字符是 "g" 。当从该字符流中读出前六个字符 “google" 时,第一个只出现一次的字符是"l"。

数据范围:字符串长度满足 ,字符串中出现的字符一定在 ASCII 码内。
进阶:空间复杂度 ,时间复杂度

后台会用以下方式调用 Insert 和 FirstAppearingOnce 函数
string caseout = "";
1.读入测试用例字符串casein
2.如果对应语言有Init()函数的话,执行Init() 函数
3.循环遍历字符串里的每一个字符ch {
Insert(ch);
caseout += FirstAppearingOnce()
}
2. 输出caseout,进行比较。

输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
示例1

输入

"google"

输出

"ggg#ll"
示例2

输入

"abcdee"

输出

"aaaaaa"
推荐
利用一个int型数组表示256个字符,这个数组初值置为-1.
没读出一个字符,将该字符的位置存入字符对应数组下标中。
若值为-1标识第一次读入,不为-1且》0表示不是第一次读入,将值改为-2.
之后在数组中找到>0的最小值,该数组下标对应的字符为所求。
public class Solution {
    //Insert one char from stringstream
    private int[] occurence = new int[256];
    private int index;
    
    public Solution(){
        for(int i=0;i<256;i++){
            occurence[i] = -1;
        }
        index = 0;
    }
    void Insert(char ch)
    {
        if(occurence[ch] == -1)
            occurence[ch] = index;
        else if(occurence[ch] >= 0)
            occurence[ch] = -2;
        
        index++;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        char ch = '\0';
        int minIndex = Integer.MAX_VALUE;
        for(int i=0;i<256;i++){
            if(occurence[i] >=0 && occurence[i]<minIndex){
                ch = (char)i;
                minIndex = occurence[i];
            }
        }
        if(ch == '\0')
            return '#';
        return ch;
    }
}

编辑于 2015-08-18 23:07:59 回复(36)

Java,借助 LinkedHashSet 记录只出现了一次的元素,并且还能保存他们的先后出现顺序。

import java.util.*;
public class Solution {
    LinkedHashSet<Character> once = new LinkedHashSet<>();
    HashSet<Character> existed = new HashSet<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if (existed.contains(ch)) {
            return;
        }

        if (once.contains(ch)) {
            once.remove(ch);
            existed.add(ch);
        }
        else {
            once.add(ch);
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        Object[] chars =  once.toArray();
        if (chars.length == 0) {
            return '#';
        }
        else {
            return (char) chars[0];
        }
    }
}
编辑于 2024-02-08 17:54:41 回复(0)
import java.util.*;
public class Solution {
//LinkedHashMap 顺序存储
    LinkedHashMap<Character,Integer> hashMap = new LinkedHashMap<>();

    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(!hashMap.containsKey(ch)){
            hashMap.put(ch,1);
        }else{
            hashMap.put(ch,hashMap.get(ch)+1);
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        // Iterator = hashMap.Iterator();
        // for(char tem : hashMap.keySet() ){
           
        //     System.out.println( tem + " " +hashMap.get(tem));
           
        // }
        for(char tem : hashMap.keySet() ){
            if(hashMap.get(tem)==1){
                return tem;
            }
        }
        return '#';
    }
}


发表于 2023-02-17 20:07:22 回复(0)
import java.util.*;
public class Solution {
    
    public Solution(){
        System.out.println("***泥马");
    }
    //Insert one char from stringstream
    private StringBuilder sb=new StringBuilder();
    private HashMap<Character,Integer> map=new HashMap<>();
    private int nowindex=0;
    public void Insert(char ch)
    {
        if(map.containsKey(ch)){
            map.put(ch,map.get(ch)+1);
        }else{
            map.put(ch,1);
        }
        sb.append(ch);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        for(int i=nowindex;i<sb.length();i++){
            if(map.get(sb.charAt(i))==1){
                nowindex=i;
                return sb.charAt(i);
            }
        }
        return '#';
    }
}

发表于 2022-08-10 11:17:53 回复(0)
public class Solution {
    
    //用来记录每个字符出现的次数,根据ASCII表可知,一共只有127个字符,固然定义数组长度为127
    int[] strs = new int[127];
    //用来判断优先级,即出现的早晚
    int[] priority = new int[127];
    int count = 0;
    
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        //记录ch字符的出现次数
        strs[ch]++;
        //保存ch第一次出现时对应的count值,count值越小,表示出现的越早
        if(priority[ch] == 0){
            
            //保存ch第一次出现时对应的count值
            priority[ch] = count;
            //自增
            count++;
        }
    }
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        //第一个不重复的字符
        char c = '#';
        //优先级
        int pri = 999;
        
        //计算第一个不重复的字符
        for(int i = 0 ; i < strs.length ; i++){
            //表示i字符只出现一次
            if(strs[i]==1){
                if(priority[i] < pri){
                    //i字符对应的优先级赋值给pri
                    pri = priority[i];
                    //当前第一个不重复的字符
                    c = (char)i;
                }
            }
        }
        
        return c;
    }
}


发表于 2022-05-19 19:57:58 回复(0)
用队列 先进先出 然后有重复的就删了他
import java.util.*;

public class Solution {
    //Insert one char from stringstream
    public Queue<Character> queue=  new LinkedList<>();
   private int[] cnts = new int[128];
   
    public void Insert(char ch)
    {
        cnts[ch]++;
        queue.add(ch);
        while (!queue.isEmpty() && cnts[queue.peek()] > 1)
        queue.poll();
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
      return queue.isEmpty() ? '#' : queue.peek();
    }
}

发表于 2022-04-19 21:06:51 回复(0)
利用的查看字符是否的位置相同来判断是是否值第一次出现且不重复(和题目第一个只出现一次的字符)
public class Solution {
    String s = "";
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        s += ch;
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
         for (int i = 0; i < s.length(); i++) {
            if (s.indexOf(s.charAt(i)) == s.lastIndexOf(s.charAt(i))) {
                return s.charAt(i);
            }
        }
        return '#';
    }
}

发表于 2022-02-08 21:55:23 回复(0)
解法1:哈希,空间复杂度o(n),时间复杂度o(n方)
import java.util.*;
public class Solution {
    // 解法1:有序HashMap
    
    // 用LinkedHashMap来维持插入顺序,这点很重要
    LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
    //Insert one char from stringstream
    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()
    {
        // 遍历LinkedHashMap,查找首个出现次数为1的字符
        for(Map.Entry<Character,Integer> e : map.entrySet()){
            if(e.getValue()==1)
                return e.getKey();
        }
        // 如果没找到,直接返回#
        return '#';
    }
}
解法2:队列+数组,空间复杂度o(n),时间复杂度o(n)
import java.util.*;
public class Solution {
    // 解法2:数组+队列
    
    // 定义数组,索引为ascii编号,值为出现次数
    int arr[] = new int[256];
    // 定义队列,维持队首为“首个不重复字符”
    Queue<Character> queue = new LinkedList<>();
    
    // 每次从字符流中读取一个字符
    public void Insert(char ch)
    {
        // 如果从未出现过
        if(arr[ch]==0){
            // 对应字符出现次数+1
            arr[ch]+=1;
            // 加入队列
            queue.offer(ch);
        }else{
            queue.remove(ch);
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        // 如果队列为空,说明没有只出现一次的字符,直接返回#
        if(queue.isEmpty())
            return '#';
        // 否则队首即为只出现一次的字符
        else
            return queue.peek();
    }
}


发表于 2022-02-03 18:52:02 回复(1)
import java.util.*;
public class Solution {
    public boolean[] mark = new boolean[130];
    public List<Character> list = new ArrayList<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(list.contains(ch)){
            mark[ch]=true;
            list.remove((Character)ch);
        }
        else if(!mark[ch]) list.add(ch);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if(list.size() == 0) return '#';
        else return list.get(0);
    }
}
发表于 2022-01-28 15:49:27 回复(0)
public class SolutionJZ75{
        private HashMap<Character, Integer> map = new HashMap<>();
        private ArrayList<Character> list = new ArrayList<>();
        public void insert(char ch){
            if(!map.containsKey(ch)){
                map.put(ch, 1);
                list.add(ch);
            }else {
                int i = map.get(ch);
                if(i == 1){
                    map.replace(ch, 0);
                    list.remove((Character) ch); // remove必须是一个类型,不能是基本类型。如果是基本类型的话,就是index了
                }
            }
        }
        public char firstAppearingOnce(){
            if(list.size() == 0){
                return '#';
            }
            return list.get(0);
        }
    }

发表于 2022-01-21 22:52:31 回复(1)
    int arr[] = new int[130];
    List<Character> list = new ArrayList<>();

    public void Insert(char ch) {
           
        //优化,只有不重复的ch才保存,减少循环次数
          if(arr[ch] == 0)
             list.add(ch);
        
            arr[ch]++;
         
        
    }

    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
        for (int i = 0; i < list.size(); i++) {
            char t = list.get(i);
            if (arr[t] == 1) {
                return t;
            }
        }
        return '#';
    }

发表于 2021-08-24 18:26:34 回复(0)
JAVA实现 用一个LinkedHashMap投机取巧
import java.util.*;
public class Solution {
    LinkedHashMap<Character,Integer> map = new LinkedHashMap<Character,Integer>();
    char single='#';
    public void Insert(char ch)
    {
        if(!map.containsKey(ch))
        {
            map.put(ch,0);
            if(single=='#')
                single=ch;
        }
        else
        {
            map.put(ch,1);
            if(single == ch)
            {
                single = '#';
                for(Map.Entry<Character,Integer> entry: map.entrySet())
                {
                    if(entry.getValue()==0)
                    {
                        single = entry.getKey();
                        break;
                    }
                }
                
            }
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        return single;
    }
}


发表于 2021-08-21 17:06:19 回复(0)
import java.util.*;

public class Solution {
    
    private Map<Character, Integer> map;
    
    public Solution() {
        map = new LinkedHashMap<>();
    }
    
    //Insert one char from stringstream
    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() {
        for(Character c : map.keySet()) {
            if(map.get(c) == 1) {
                return c;
            }
        }
        return '#';
    }
}

发表于 2021-08-14 15:38:36 回复(2)
import java.util.*;
public class Solution {
    private Deque<Character> deque = new ArrayDeque<>();
    private int[] count = new int[128];
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if (count[ch] == 0) {
            deque.offer(ch);
        }
        count[ch]++;
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        while (!deque.isEmpty() && count[deque.peek()] > 1) {
            deque.poll();
        }
        return deque.peek() == null ? '#' : deque.peek();
    }
}

发表于 2021-07-30 12:29:43 回复(0)
使用两个linkedlist:
import java.util.LinkedList;

public class Solution {
    LinkedList<Character> queue = new LinkedList<>(); // 用来存出现一次的字符(按顺序)
    LinkedList<Character> exits = new LinkedList<>(); // 用来保存原字符流

    public void Insert(char ch)
    {
        if (exits.contains(ch)) {
            // queue.remove(ch); 这样会报越界异常。
            if (queue.contains(ch)) {
                queue.remove(new Character(ch));
            }
            exits.addLast(ch);
        } else {
            queue.addLast(ch);
            exits.addLast(ch);
        }
    }
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if (queue.isEmpty()) {
            return '#';
        } else {
            return queue.getFirst();
        }
    }
}
看了题解之后想到的改进:
import java.util.LinkedList;

public class Solution {
    // 改造 : 由于ascii字符之后128个,用一个数组存即可
    LinkedList<Character> queue = new LinkedList<>();// 用来存出现一次的字符(按顺序)
    int[] times =new int[128];

    public void Insert(char ch) {
        if (times[ch] == 0) {
            queue.addLast(ch);
        } else {
            queue.remove(new Character(ch));
        }
        times[ch]++;
    }

    public char FirstAppearingOnce() {
        if (queue.isEmpty()) {
            return '#';
        } else {
            return queue.getFirst();
        }
    }
}



编辑于 2021-05-03 21:45:07 回复(0)
public class Solution {
    private int[] cnts = new int[256];
    private Queue<Character> queue = new LinkedList<>();
    public void Insert(char ch) {
       cnts[ch]++;
       queue.offer(ch);
       while (!queue.isEmpty() && cnts[queue.peek()] > 1) {
           queue.poll();
       }
    }

    public char FirstAppearingOnce() {
        return queue.isEmpty() ? '#' : queue.peek();
    }
}

编辑于 2021-03-19 20:00:26 回复(0)
import java.util.*;
public class Solution {
    /*
    读了半天,看了半天解析,然后再调试了半天才知道这个题目函数是用来干啥,
    题目意思是啥,我真的由瓦依!
    题目意思:就是 Insert 函数是用来接收每次的从字符流传递过来的一个字符举例:
    第一次:Insert 传递过来的一个字符: g
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(g) 显然是 g
    第二次:Insert 传递过来一个字符: o
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(go) 显然是还是 g
     第三次:Insert 传递过来一个字符: o
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(goo) 显然是还是 g
     第四次:Insert 传递过来一个字符: g
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(goog) 显然没有,则返回 #
     第五次:Insert 传递过来一个字符: l
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(googl) 显然是 l
     第六次:Insert 传递过来一个字符: e
    就要在 FirstAppearingOnce 函数中去判断当前第一个只出现一次的字符(google) 显然是还是 l
     
    所以就要走 Insert 函数中进行获取,然后在 FirstAppearingOnce 进行返回
    */
    Set<Character> set=new HashSet<>();
    ArrayList<Character> list=new ArrayList<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        //java Set 加入时候重复就会返回 false,没有重复返回true
        if(set.add(ch))
        {
            list.add(ch);
        }else
        {
            //这一块判断因为可能会重复好几次
            if(list.contains(ch))
                list.remove(new Character(ch));
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if(list.size()>0)
            return list.get(0);
        else
            return '#';
    }
}

发表于 2021-01-31 21:44:33 回复(0)