【剑指offer】字符流中第一个不重复的字符
题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
如果当前字符流没有存在出现一次的字符,返回#字符。
解题思路
方法1:
最简单的想法,用字符串str
记录字符流中的每一个字符ch
,同时利用一个数组hash
记录每一个字符ch
对应出现的次数,即hash[ch]
,直至字符流中的所有字符被读取。然后,按照str
中的字符顺序,遍历hash
,找到第一个等于只出现一次的字符,即第一个hash[ch]=1
对应的字符ch
,返回。若没有存在出现一次的字符,则返回#
。
注:标准ASCII共有128个字符,还有128个扩展ASCII以表示特殊符号字符、外来语字符和图形符号。在这题里,hash的大小设为128即可满足题意。
class Solution
{
public:
string str;
char hash[128] = {0};
//Insert one char from stringstream
void Insert(char ch)
{
str += ch;
hash[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
for(char ch:str){
if(hash[ch] == 1){
return ch;
}
}
return '#';
}
};
说明:
for(char ch:str){
...
}
//相当于
char ch;
for(int i=0;i<str.length();i++){
ch = str[i]
}
方法2:
这是借鉴讨论区的方法。
思路:
1、用一个128大小的数组统计每个字符出现的次数
2、用一个队列,如果第一次遇到ch
字符,则插入队列;其他情况不在插入
3、判断队首元素是否只出现一次,如果是,直接返回;否则删除首元素,继续第3步骤
class Solution
{
public:
//Insert one char from stringstream
void Insert(char ch)
{
++hashArray[ch-'\0'];
if( hashArray[ch-'\0'] == 1){
data.push_back(ch);
}
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
while( !data.empty() && hashArray[data.front()] >= 2 ){
data.pop_front();
}
if( data.empty() )
return '#';
return data.front();
}
private:
unsigned char hashArray[128];
deque<char> data;
};
方法2中使用了双向开口的deque
队容器,也就是可以在队列的头尾两端分别做元素的插入和删除操作。vector
是单向的队容器,若要在头部插入元素,则效率很低。deque
和vector
容器的差异有:
(1) deque
可以以常数项实践对头部进行元素的插入和删除操作;vector
不行,服从先进先出 (FIFO) 原则。
(2) deque
随时可以增加一段新的空间,是由动态的分段连续空间组成的;vector
如果空间不足,则要重新配置一块更大的空间,将原来的元素复制到新的空间中,然后释放原来的空间。
(3) deque
的迭代器不是普通的指针,运算会较为复杂,不常用。
关于deque
的一些常用操作:
//初始化
deque<T> deqT;//默认构造形式
// 大小操作
deqT.size();//返回容器中元素的个数
deqT.empty();//判断容器是否为空
//数据的存取
deqT.at(idx);//返回索引idx所指的数据
deqT.front();//返回第一个数据。
deqT.back();//返回最后一个数据
//双端的插入和删除
deqT.push_back(elem);//在容器尾部添加一个数据
deqT.push_front(elem);//在容器头部插入一个数据
deqT.pop_back();//删除容器最后一个数据
deqT.pop_front();//删除容器第一个数据
//插入操作
deqT.insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
deqT.insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
//删除操作
deqT.clear();//删除所有数据
deqT.erase(beg,end);//删除[beg,end)的数据,返回下一个数据的位置。
deqT.erase(pos);//删除pos位置的数据,返回下一个数据的位置。
参考:
[1]: https://www.nowcoder.com/profile/320158/codeBookDetail?submissionId=1500461
[2]: https://blog.csdn.net/weixin_42462202/article/details/87537503
推荐阅读
-
剑指offer27:按字典序打印出该字符串中字符的所有排列
-
PHP获取字符流中第一个不重复字符的方法
-
剑指offer JZ54 字符流中第一个不重复的字符 Python 多解
-
剑指 offer代码最优解析——面试题35第一个只出现一次的字符
-
20200329-剑指offer-面试题48. 最长不含重复字符的子字符串(滑动窗口)
-
第一个只出现一次字符的位置 牛客网 剑指Offer
-
剑指offer——第一个只出现一次的字符位置
-
《剑指offer》-- 两个链表的第一个公共结点、链表中环的入口结点、删除链表中的重复结点
-
剑指offer两个面试案例 把字符串转换成整数 树中两个节点的最低公共祖先
-
剑指 Offer 48. 最长不含重复字符的子字符串