题目描述:

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)
用map实现字符统计,将字符串中所有字符加进map中,再根据字符的顺序,依次查找每一个字符出现的个数。

方法一:用map统计字符个数

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        int len=str.size();
        map<char,int>mp;
        for(int i=0;i<len;i++)
            mp[str[i]]++;
        for(int i=0;i<len;i++)
        {
            if(mp[str[i]]==1)
                return i;
        }
        return -1;
    }
};

方法二:用数组统计字符个数

将统计结果放在一个数组中,字符对应的ASCII为数组下标,数组中元素为该元素出现的次数。

A-Z的ASCII码的对应的为41-90
a-z的ASCII码的对应的为97-122

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        int len=str.size();
        int a[100]={0};
        for(int i=0;i<len;i++)
            a[str[i]-'A']++;
        for(int i=0;i<len;i++)
            if(a[str[i]-'A']==1)
                return i;
        return -1;
    }
};

对ASCII范围没有概念,还有一种方法,26个英文字符算上大小写,一共52个字符,建一个大小为52的数组,每个字符对应一个下标。

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        int len=str.size();
        int a[52]={0};
        for(int i=0;i<len;i++)
        {
            if(str[i]>='a'&&str[i]<='z')
                a[str[i]-'a']++;
            else
                a[str[i]-'A'+26]++;
        }
        for(int i=0;i<len;i++)
        {
            if(str[i]>='a'&&str[i]<='z')
            {
                if(a[str[i]-'a']==1)
                    return i;
            }
            else
            {
                if(a[str[i]-'A'+26]==1)
                    return i;
            }

        }
        return -1;
    }
};

方法三:用基于hash的map统计字符个数

思路:先统计每个字符出现的次数,然后遍历字符,找到第一个只出现一次的字符。
1、不要使用基于二叉树的map,会增加复杂度;
2、c++的基于hash的map是unordered_map;
3、也可以用数组实现一个简单的hash map;

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        int len=str.size();
        int hash[256]={0};
        for(int i=0;i<len;i++)
            hash[str[i]]++;
        for(int i=0;i<len;i++)
            if(hash[str[i]]==1)
                return i;
        return -1;
    }
};