【字符串】字符串中的第一个唯一字符(C语言)(Hash及其优化)

【字符串】字符串中的第一个唯一字符(C语言)(Hash及其优化)
乍一看这题,非常简单,直接从头开始暴力搜索,双重循环搞定。1min就敲出了代码:
(错误示范)

#include<string.h>

int firstUniqChar(char * s){
    int len=strlen(s);
    int i,j;
    int flag;
    for (i=0; i<=len-1; i++)
    {
        flag=0;
        for (j=0; j<=len-1; j++)
        {
            if (s[i]!=s[j] && i!=j)    flag++;
        }
        if (flag==len-1)   return i;
    }
    return -1;
}

但是执行以后就gg:
【字符串】字符串中的第一个唯一字符(C语言)(Hash及其优化)
这很显然是因为双重for循环时间复杂度为O(N^2),对于很长的字符串,耗费的时间就会相当多,必然是超限。
那么,我们就不得不想个办法降低复杂度O(N)了。


之前,在初步学习C语言时,我有讲过所谓的“计数器judge”(我自己起的名字)的方法。
看“计数器judge”点这里!
这道题其实可以用计数器,降低复杂度。最后实现的代码是:

int firstUniqChar(char * s){
    int len=strlen(s);
    int i;
    int judge[1000]={0};

    for(i=0; i<=len-1; i++)
    {
        judge[s[i]]++;
    }

    for (i=0; i<=len-1; i++)
    {
        if (judge[s[i]]==1)  return i;
    }
    return -1;
}

虽然使用了两次for循环,但是复杂度压低到了O(N),自然也就通过了:
【字符串】字符串中的第一个唯一字符(C语言)(Hash及其优化)
当然,这个计数器还可以做优化处理,让他的运行速率更快一些。
之前的代码judge开辟了1000个空间去存储,而其实大可不必,我们可以这样来做:

int firstUniqChar(char * s){
    int len=strlen(s);
    int i;
    int judge[26]={0};

    for(i=0; i<=len-1; i++)
    {
        judge[s[i]-'a']++;
    }

    for (i=0; i<=len-1; i++)
    {
        if (judge[s[i]-'a']==1)  return i;
    }
    return -1;
}

唯一的区别在于judge只开放了26个空间,计数器的下标是“该元素ASCII-字符a的ASCII”的值,这样就可以防止给judge分配多余的无用的空间。这样做,效率更高了:
【字符串】字符串中的第一个唯一字符(C语言)(Hash及其优化)


在笔者的学习中,我了解到这种所谓的“计数器judge”,其本质是“哈希表”(Hash Table)。

judge数组是一个简单的哈希表,judge数组的下标是字符对应的ASCII码,也就是该哈希表的关键词(key)。在一些统计、查找重复的问题中,哈希表是首选的数据结构。

在日后的学习中,我会对哈希表做更深入的学习,现在就姑且理解到这一层吧。

上一篇:E. Email Destruction---大模拟


下一篇:函数调用顺序,pow函数2021.3.2