剑指offer刷题-字符流中第一个不重复的字符(LinkedHashMap)

题目描述

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

输出描述:

如果当前字符流没有存在出现一次的字符,返回#字符。
用例:
“google”
对应输出应该为:
“ggg#ll”
分析:

  1. 在前三个字符时,第一个不重复的字符始终是g,因此一直输出g;
  2. 到第四个字符g因为出现的g和o此时均为重复出现,所以输出#,表示不存在只出现一次的字符。
    3)之后输入le,l是第一个只出现一次的字符,所以输出ll。

思路:

有两个函数:1)Insert的输入为字符,输出为空,主要实现字符流的输入,因为字符流不同于字符串,所以需要容器来存储字符流,以便后续进行字符的出现次数查找。

发现有人用HashMap存储字符流,但是由于HashMap是无序存储的,即不会按照输入的顺序存储,而题目要求是找出第一个只出现一次的字符,因此对存储顺序要求是按照输入的顺序。

所以选用LinkedHashMap存储字符流,是按照插入顺序存储的,满足题目要求。

2)FirstAppearingOnce函数用来找到第一个重复出现的字符。

将字符作为LinkedHashMap的键,其出现次数作为值。遍历LinkedHashMap,当存在只出现一次的字符即值为1时,就输出对应的键即字符,否则输出#。

import java.util.*;
public class Solution {
    char c ='#';
    //Insert one char from stringstream
    LinkedHashMap<Character,Integer> map = new LinkedHashMap<Character,Integer>();
    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> entry : map.entrySet()) 
        {
            while((int)entry.getValue() == 1)
            {
                return (char)entry.getKey();
            }
        }
        return c;
    }
}

PS:关于集合详解

一、集合体系

在这里插入图片描述
Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。而是让接口Set和List继承Collection接口。

Map接口是Java.util包中的另一个接口,它和Collection接口是相互独立的,都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value。

所有的集合类都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含以下三种方法:
(1).hasNext()是否还有下一个元素。
(2).next()返回下一个元素。
(3).remove()删除当前元素。

1、单列集合Collection

List和Set的区别

ListSet
有序无序
可重复不可重复

ArrayList和LinkedList的区别

对比ArrayListLinkedList
底层数据结构数组双向链表
查找效率有下标,查找快查找慢
增删效率增删慢增删快

Set的类

AbstractSetHashSetTreeSet
无序无序二叉排序树,有序
不可重复不可重复不可重复

2、双列集合Map

Map集合中存储的是键值对键不能重复,值可以重复。根据键得到值,对Map集合遍历时先得到键的Set集合,对set集合进行遍历,得到相应的值。

HashMapHashTableConcurrentHashMapTreeMapLinkedHashMap
无序无序无序红黑树,自然顺序链表结构,有序(插入顺序)
线程不安全线程安全线程安全且锁分离线程不安全

(1)HashMap

  1. HashMap继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口,底层数据结构为数组(table)+链表(entry),每个entry对应着一个table的索引页,对应着一个唯一的hash地址值

  2. key、value都可以为null,其中HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null。此外,HashMap中的映射不是有序的。

  3. HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量是哈希表中的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

  4. 通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

  5. HashMap不支持线程的同步(即任一时刻可以有多个线程同时写HashMap),可能会导致数据的不一致,因此线程不安全。如果需要同步,可以用ConcurrentHashMap。

  6. 遍历速度和他的容量有关。

(2)HashTable

  1. 与 HashMap类似,它继承自Dictionary类。

  2. Hashtable不允许记录的键或者值为空

  3. 它支持线程同步,线程安全(即任一时刻只有一个线程能写Hashtable),性能开销较大

(3)LinkedHashMap

  1. 拥有 HashMap 的所有特性,比 HashMap 多维护了一个双向链表,所以保存记录插入顺序

  2. 遍历比HashMap慢。不过有种情况例外:当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢。因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

(4)TreeMap

  1. TreeMap 的底层就是一颗红黑树,并且它是按照 key 的自然顺序(或者指定排序)排列。
  2. 它的 containsKey , get , put和remove 方法的时间复杂度是 log(n) .
  3. TreeMap实现SortMap接口.

(5)ConcurrentHashMap

  1. ConcurrentHashmap区别于hash的分段锁
    在这里插入图片描述
  2. 使用Segment同步方法,而且Segment又继承了ReentrantLock,所以实现了分布式锁,保证线程安全的同时还提高了效率。

3、主要实现类区别总结

  1. Vector和ArrayList
VectorArrayList
基于数组基于数组
线程安全线程不安全
超出长度时,扩为两倍,因此 适用于数据量较大超出长度时,扩为1.5倍
索引数据快,插入数据慢索引数据快,插入数据慢
  1. arraylist和linkedlist
arraylistlinkedlist
基于动态数组基于链表
检索快,添加/删除慢检索慢,添加/删除快
  1. HashMap与TreeMap
HashMapTreeMap
通过hashcode快速查找
排列顺序是不固定的自然顺序

4)HashTable 和HashMap

HashTableHashMap
线程安全线程不安全
允许一个key为空,多个Value为空Key和value均不允许为空
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值