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

题目描述

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"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++中,可以在数组定义的时候对其进行初始化:

[cpp]  view plain  copy
  1. int a1[3] = {1, 2, 3};  
  2. int a2[3] = {0};                    //将数组a2各个元素赋值为0。  
  3. int a3[] = {1, 2, 3};  
  4. char s1[3] = {'a''b''c'};  
  5. char s2[] = "abc";  



但是以下赋值方式是错误的:
[cpp]  view plain  copy
  1. int a4[3] = {};                    //无法通过编译;  
  2. char s3[3] = "abc";                  //编译错误,数组越界。  
上一段中,第二个例子之所以错误,是因为“abc”是4个字符,除了a/b/c三个字符之外,还有一个结束字符 '\0' 。


在赋值过程中最容易误解的地方是误以为以下代码将a5全赋值为1。
[cpp]  view plain  copy
  1. char a5[3] = {1};                //这行代码之后,数组a5各项值分别为1, 0, 0。  
这是因为在C/C++中,“如果初始化时指定的的元素个数比数组大小少,剩下的元素都回被初始化为0。”因此我们便可以通过int a2[3] = {0};来将数组a2全赋值为0。


要将数组a5的各个元素均赋值为1,可以采用如下方法:
[cpp]  view plain  copy
  1. memset(a5, 1, 3);  
其中memset在包含在头文件string.h中。


特别需要注意的是,memset的根据针对字节进行操作的,因此以下代码并不会得到我们期待的结果。
[cpp]  view plain  copy
  1. int a6[3];  
  2. memset(a6, 1, 3 * sizeof(int));    //在32位机器下,a6[0]~a6[2]的值均为16843009。  


要对数组进行批量赋值,可以使用memcpy函数。或者将数组封装在一个struct中。


猜你喜欢

转载自blog.csdn.net/nichchen/article/details/80498049