面试题50:第一个只出现一次的字符

该博客主要讨论如何在字符串中找到第一个只出现一次的字符。介绍了两种方法:顺序查找和哈希表查找。顺序查找的时间复杂度为O(n^2),而哈希表查找可以更高效地解决这个问题。博客还探讨了如何使用基于数组和STL中的unordered_map创建哈希表,并解释了在字符流中实时查找第一个唯一字符的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试题50:第一个只出现一次的字符

题目描述(1)字符串中第一个只出现一次的字符

在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”,则输出‘b’。并返回它的位置, 如果没有则返回 -1(需要区分大小写)。

思路

在字符串中查找某个字符——查找

查找算法:顺序查找、二分查找、二叉排序树查找、哈希表查找

二分查找和二叉排序树,针对有序的数组

1.使用顺序查找:

​ 从头到尾依次取字符,遍历后面的字符与取出的字符比较,若无相同的字符则返回这个字符,否则取下一个字符重复上述过程。时间复杂度为O(n2

2.哈希表查找:

​ 把字符作为键,遍历字符串,字符的个数作为值。产生哈希表。再按照字符串的顺序从头到尾开始查找第一个值为1的键。

基于数组创建哈希表

​ 键值是字符,char的取值范围较小(0-255),所以可以直接开一个大小为256的数组,以数组下标作为键值(字符ASCII码)。当键值范围较大时(如unicode),不适合用数组创建哈希表。

int FirstNotRepeatingChar(string str) {
    //0.特殊
    auto len = str.size();
    if(len == 0)
        return -1;
    
    //1.初始化基于数组的哈希表
    int hashTable[256] = {0};
    
    //2.构建哈希表
    for(int i = 0; i<len; ++i){
        ++hashTable[str[i]];
    }
    
    //3.哈希表查找
    for(int i = 0; i<len; ++i){
        if(hashTable[str[i]] == 1)
            return i;
    }
    
    return -1;
}
基于STL中unordered_map创建哈希表

关联容器:按关键字来保存和访问。

顺序容器:按元素的位置顺序保存和访问。

类型含义
map关联数组 保存键-值对(按顺序)
multimap关键字可重复出现的map
unordered_map用哈希函数组值的map (不按顺序)
unordered_multimap哈希组值的map,关键字可重复

map和unordered_map支持下标和at函数。

下标操作的返回值是左值,既可读也可写。

int FirstNotRepeatingChar(string str) {
    //1.定义哈希表
    unordered_map<char, size_t> char_count;
    
    //2.构建哈希表
    for(auto a: str)
    {
        ++char_count[a];//没有数组越界问题,若a不再map中,将插入这个元素
    }
    
    //3.哈希表查找
    for(int i = 0; i<str.size(); ++i){
       if(char_count[str[i]]== 1)//使用str[i]来遍历 按顺序 用map的迭代器不是按照字符串的顺序
            return i;
    }

    return -1;
}

题目描述(2)

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

思路

每插入一个字符,哈希表记录字符位置(第一次出现),或设置特殊值(多次出现)。最后遍历哈希表,查找最小值(最先出现),它对应的键即字符的ASCII码。

class Solution
{
public:
    /*Solution():index(1){
        for(int i = 0; i<256; ++i){
            hashTable[i] = 0;
        }
    }*/
  //Insert one char from stringstream
    void Insert(char ch)
    {
        if(hashTable[ch] == 0){
            hashTable[ch] = index;//错误:=写成 == 
        }
        else if(hashTable[ch] > 0){
            hashTable[ch] = -1;
        }
        ++index;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        int minIndex = 100;//numeric_limits<int>::max();
        char ch = '\0';
        for(int i = 0; i<256; ++i){
            if(hashTable[i] < minIndex && hashTable[i] >0){
                minIndex = hashTable[i];
                ch = (char)i;
            }
        }
        if(ch == '\0')
            return '#';
        return ch;
    }
private:
    int hashTable[256] = {0};
    int index = 1;

};

Note

在使用数组下标时,通常将其定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计得足够大以便能表示内存中任意对象的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值