题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
思路一:用一个辅助队列和辅助计数数组,在顺序读取字符串时,按顺序存储出现的字符,并计数;最后返回第一个只出现一次的单个字符。
代码一:
class Solution { public: //Insert one char from stringstream void Insert(char ch) { ++cnt[ch]; if(cnt[ch] == 1) q.push(ch); } //return the first appearence once char in current stringstream char FirstAppearingOnce() { while(!q.empty() && cnt[q.front()] >= 2) q.pop(); //排除非只出现一次的字符 if(q.empty()) return '#'; return q.front(); } private: queue<char> q; //按顺序存储出现过1次的字符 unsigned int cnt[128]; //ascii表共有128个字符 };
思路二:
只选用数组作为辅助,数组记录每个字符出现的次数和位置,若出现多次则索引为-1,若不出现则索引为0,若出现了一次则索引为“出现位置+1”,最后对128个字符进行循环,对出现位置进行判断筛选,即可找到最先出现的字符。
代码二:
class Solution { public: //Insert one char from stringstream void Insert(char ch) { if(cnt[ch] == 0) { //0表示从未出现,-1表示出现多次,其余表示只出现一次且索引值为“位置+1“ cnt[ch] = idx+1; } else if(cnt[ch] > 0){ cnt[ch] = -1; } ++idx; } //return the first appearence once char in current stringstream char FirstAppearingOnce() { char res = '#'; int mn = INT_MAX; for(int i = 0; i < 128; ++i) { if(cnt[i] > 0 && cnt[i] < mn) { res = (char)i; mn = cnt[i]; } } return res; } private: int idx = 0; //每个字符的下标索引 int cnt[128] = {0}; //ascii表共有128个字符 };
注意:
在C/C++中,可以在数组定义的时候对其进行初始化:
- int a1[3] = {1, 2, 3};
- int a2[3] = {0}; //将数组a2各个元素赋值为0。
- int a3[] = {1, 2, 3};
- char s1[3] = {'a', 'b', 'c'};
- char s2[] = "abc";
但是以下赋值方式是错误的:
- int a4[3] = {}; //无法通过编译;
- char s3[3] = "abc"; //编译错误,数组越界。
在赋值过程中最容易误解的地方是误以为以下代码将a5全赋值为1。
- char a5[3] = {1}; //这行代码之后,数组a5各项值分别为1, 0, 0。
要将数组a5的各个元素均赋值为1,可以采用如下方法:
- memset(a5, 1, 3);
特别需要注意的是,memset的根据针对字节进行操作的,因此以下代码并不会得到我们期待的结果。
- int a6[3];
- memset(a6, 1, 3 * sizeof(int)); //在32位机器下,a6[0]~a6[2]的值均为16843009。
要对数组进行批量赋值,可以使用memcpy函数。或者将数组封装在一个struct中。