剑指Offer50.第一个只出现一次字符

  • 剑指Offer50.第一个只出现一次字符

  • 题目1:
    输入一个字符串s,返回第一个出现次数为1的字符,若没有这样的字符,就返回一个空格;
    字符仅有26个小写字母;

  • 思路:
    1.哈希表 + 两次遍历:O(n),O(1)

class Solution {
    
    
public:
    char firstUniqChar(string s) {
    
    
        int v[26] = {
    
    0};
        for (auto c : s) {
    
    //第一次遍历s,统计每个字符出现的次数
            v[c - 'a']++; 
        }
        for (auto c : s) {
    
    //第二次遍历s
            if (v[c- 'a'] == 1) return c;//找到第一个次数为1的字符
        }
        return ' ';
    }
};
  • 题目2:64.字符流中第一次只出现一次的字符
  • 思路:
    类似双顶堆求数据流的中位数那道题,本题也是一个字符流,随着不断insert输入,随时可能firstAppearingOnce查第一次只出现一次的字符;
    这种动态的题,肯定不能通过一个变量维护,只能通过一个动态变化的数据结构,不断更新目标值;
    随着insert输入,自然会出现重复字符,之前这些只出现一次的字符自然会慢慢消失,而第一次只出现一次的字符也一定是满足单调向后更新的,因为某字符x如果是目前第一个只出现一次的字符,那么它前面所有字符一定都是重复字符,随着不断输入,也可能输入x导致目标字符x也由于重复而消失,下一个目标字符一定出现在x的后面位置(也正因如此,y总的方法使用queue);
//自己写的
//劣势在于使用集合而不是映射,因此无法存对应字符出现的次数,因此当insert一个重复字符时,它可能是所求的目标字符,也可能是后面的,例如google,insert第二个o时,当前所求的目标字符(即第一次只出现一次的字符仍然是g),因此为了标注该字符重复了,要么删掉,要么做某些标记,但不论哪种,总需要遍历vector先找到该重复字符,才能删除或标记;而y总的方法,无论某个字符是第1次出现还是重复字符,操作都是++count[ch]
//至于查firstAppearingOnce时,采用队列的话,由于重复元素一旦出现就在insert中删掉了,队首(如果有的话)始终就是目标字符;而我的方法,每次都要遍历vector,去找到第一个false对应的字符,即便前面一段已经全部都是重复字符了,在每次查firstAppearingOnce时都会白白遍历1次;
class Solution{
    
    
public:
    unordered_set<char> us;
    vector<pair<char, bool>> q;//当出现重复字符时,可以选择直接从vector中erase掉,但效率低下,因此选择用一个bool表示该字符是重复字符
    //Insert one char from stringstream
    void insert(char ch){
    
    
        if (us.find(ch) == us.end()) {
    
    
           q.push_back({
    
    ch, false});
           us.insert(ch);
        }
        else {
    
    
            for (auto& p : q)
                if (p.first == ch) p.second = true;
        }
    }
    //return the first appearence once char in current stringstream
    char firstAppearingOnce(){
    
    
        for (auto& x : q)
            if (x.second == false) return x.first;
        return '#';
    }
};
//y总
class Solution{
    
    
public:
    unordered_map<char, int> count;
    queue<char> q;
    //Insert one char from stringstream
    void insert(char ch){
    
    
        if (++count[ch] == 1) q.push(ch);//新来的字符放在队尾,留作后备军
        while (!q.empty() && count[q.front()] > 1) q.pop();//(如果队列不为空的话)始终保持队首是第一个只出现一次的字符,一旦重复就丢弃,因为下一个只出现一次的字符一定在这个队首后边
    }
    //return the first appearence once char in current stringstream
    char firstAppearingOnce() {
    
    
        return q.empty() ? '#' : q.front();
    }
};
  • 总结:
    y总NB!

猜你喜欢

转载自blog.csdn.net/jiuri1005/article/details/114337719