【剑指offer-54】20190907/03 字符流中第一个不重复的字符

【剑指offer-54】字符流中第一个不重复的字符

  • 考点:字符串
  • 时间限制:1秒
  • 空间限制:32768K
  • 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
    输出描述:
    如果当前字符流没有存在出现一次的字符,返回#字符。

思路:

看到这个问题我就想需要用hashmap来保存出现的次数。但是这里还有个问题就是,怎么样保存顺序,因为hashmap是无序的。所以借助了一个arraylist来保存出现的顺序。每次把字符push进去之后,list保存的顺序,就是字符的顺序。
接下来只要找到第一个只出现了一次的字符,return即可。

代码:
import java.util.HashMap;
import java.util.ArrayList;
    
public class Solution {
    HashMap<Character, Integer> hashmap = new HashMap();
    ArrayList<Character> list = new ArrayList();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if (hashmap.containsKey(ch)) {
            int value = hashmap.get(ch);
            hashmap.remove(ch);
            hashmap.put(ch, value + 1);
        } else {
            hashmap.put(ch, 1);
        }
        list.add(ch);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        for (int i = 0; i < list.size(); i++) {
            if (hashmap.get(list.get(i)) == 1) {
                return list.get(i);
            }
        }
        return '#';
    }
}
我的问题:

hashmap是无序的!

  1. hashmap也可以借助数组来模拟,大小为256,下标为每一个字符的ascii码值。
  2. hashmap就是用来保存出现的次数的。
  3. 一定要有一个容器记录字符出现的顺序。

其他思路1:

提供一个高效的算法:
思路:时间复杂度O(1),空间复杂度O(n)
1、用一个128大小的数组统计每个字符出现的次数
2、用一个队列,如果第一次遇到ch字符,则插入队列;其他情况不在插入
3、求解第一个出现的字符,判断队首元素是否只出现一次,如果是直接返回,否则删除继续第3步骤

分析:可以看出相同的字符只被插入一次,最多push128个,同时大多数情况会直接返回队首。所以大家不要被里面的while循环迷惑

英文字符不会逃出128个ascii码的范围,所以定义这个长度的数组
第一个ASCII码是一个空字符,所以我都是相对于进行一一排列
比如数字’0’是30,那’0’-’'等于30,就存在tmp[30]这个地方即可
注意,tmp存的是出现的子树,即’0’出现了两次,那么tmp[30]就是2

import java.util.Queue;
import java.util.LinkedList;

public class Solution {
    //Insert one char from stringstream
    Queue<Character> queue = new LinkedList();
    int list[] = new int [128];

    public void Insert(char ch)
    {
        // 如果是第一次进来,那就加入到队列中
        if (list[ch - ' '] == 0) {
            queue.add(ch);
        }
        //进来一次,就对相应坐标加一,统计出出现次数
        list[ch-' ']++;
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        // 取得时候是从队列得头部取,因为头部是比较早的数据
        //出现次数大于等于2的话就不断丢弃,直到找到第一个出现次数为1的字符跳出循环
        while(!queue.isEmpty() && list[queue.peek()-' '] >= 2){
            queue.poll();
        }
    
        //拿到这个第一个只出现一次的字符
        if(!queue.isEmpty()){
            return queue.peek();
        }
        
        return '#';
    }
}
  1. queue用了linkedlist进行实例化。
  2. queue的方法:
  • offer / add 添加
  • poll / remove 移除
  • peek / element 队首元素

其他思路2:

LinkedHashMap的有序性。

import java.util.LinkedHashMap;
import java.util.Map;

public class Solution {
    //Insert one char from stringstream
    Map<Character, Integer> map = new LinkedHashMap();
    public void Insert(char ch)
    {
        if (map.containsKey(ch)) {
            map.put(ch, map.get(ch) + 1);
        } else {
            map.put(ch, 1);
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        for (Map.Entry<Character, Integer> set : map.entrySet()) {
            if (set.getValue() == 1) {
                return set.getKey();
            }
        }
        return '#';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值