LeetCode - First Unique Character in a String

题目
Given a string, find the first non-repeating character in it and return it’s index. If it doesn’t exist, return -1.
Note: You may assume the string contain only lowercase letters.
思路1
可以建立一个哈希表,保存每一个字符的出现的位置,重复出现的字符可以用一个特殊的值,比如INT_MAX来表示。最后历遍整个表查找最小的值,也就是从未重复出现过的最靠前的字符位置。

class Solution {
public:
    int firstUniqChar(string s) {
        unordered_map<char,int> strmap;
        for(int i=0;i<s.size();i++){
            char now=s[i];
            if(strmap.find(now)!=strmap.end()){
                strmap[now]=INT_MAX;
            }else{
                strmap[now]=i;
            }
        }
        int min=INT_MAX;
        for(unordered_map<char,int>::iterator iter=strmap.begin();iter!=strmap.end();iter++){
            min=min>=(iter->second)?(iter->second):min;
        }
        return min==INT_MAX?-1:min;
    }
};

执行时间79ms,不是很理想。

思路2
哈希表更适合记录一些离散的值,比如数字,然而note指出,字符串中出现的只会是小写字母,那么完全可以建立一个数组来记录位置。
所以可以把哈希表改为数组,这样时间减少到了42ms,毕竟哈希表的访问速度比数组慢不少。

class Solution {
public:
    int firstUniqChar(string s) {
        int pos[26];
        //初始化数组
        for(int i=0;i<26;i++){
            pos[i]=-1;
        }
        //更新数组,使得每一个没有重复出现的字符保持着出现的位置
        for(int i=0;i<s.size();i++){
            int now=s[i]-'a';
            pos[now]=pos[now]<0?i:INT_MAX;
        }
        int min=INT_MAX;
        //查询数组,寻找最小值,即最早出现的位置
        for(int i=0;i<s.size();i++){
            int now=s[i]-'a';
            if(pos[now]>=0&&pos[now]<min){
                min=pos[now];
            }
        }
        return min==INT_MAX?-1:min;
    }
};

这个解法带来的问题就是,需要用一个额外的值来记录从未出现过的字符,使得最后查询的时候变得麻烦了一些。
另外,最后查询的时候其实并不需要历遍整个字符串,只需要记录第一个出现的非INT_MAX(没有重复出现),非-1(在字符串中出现过)的位置即可。
思路三
前面两个思路记录的是位置信息,然而最后查询历遍的时候发现位置信息完全可以被变量 i 所取代,所以记录的信息实际上是是否出现过以及是否重复 两点而已。那么换一个思路,记录每个字符出现的次数,可以将这两点合并为出现次数是否为1

class Solution {
public:
    int firstUniqChar(string s) {
        int times[26]={};
        int size=s.size();
        for(int i=0;i<size;i++){
            times[s[i]-'a']++;
        }
        for(int i=0;i<size;i++){
            int now = s[i]-'a';
            if(times[now]==1){
                return i;
            }
        }
        return -1;
    }
};

执行时间依然是42ms,但是代码简洁了不少。

思路4
其实这并不是新的思路,但是前面代码写错了,思路2中既然记录了位置,为什么还要历遍字符串呢,历遍一遍记录位置的数组取最小值就好了。

class Solution {
public:
    int firstUniqChar(string s) {
        int pos[26];
        //初始化数组
        for(int i=0;i<26;i++){
            pos[i]=-1;
        }
        //更新数组,使得每一个没有重复出现的字符保持着出现的位置
        for(int i=0;i<s.size();i++){
            int now=s[i]-'a';
            pos[now]=pos[now]<0?i:INT_MAX;
        }
        int min=INT_MAX;
        //查询数组,寻找最小值,即最早出现的位置
        for(int i=0;i<26;i++){
            if(pos[i]>=0&&pos[i]<min){
                min=pos[i];
            }
        }
        return min==INT_MAX?-1:min;
    }
};

执行时间39ms,果然比思路3快一点。
思路5
待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值