zoukankan      html  css  js  c++  java
  • 剑指 Offer 50. 第一个只出现一次的字符

    方法一:使用哈希表存储频数

    我们可以对字符串进行两次遍历。

    在第一次遍历时,我们使用哈希映射统计出字符串中每个字符出现的次数。在第二次遍历时,我们只要遍历到了一个只出现一次的字符,那么就返回该字符,否则在遍历结束后返回空格。

    class Solution {
    public:
        char firstUniqChar(string s) {
            unordered_map<char, int> mp;
            for (char c : s)
                mp[c]++;
            
            char res = ' ';
            for (char c : s) {
                if (mp[c] == 1) {
                    res = c;
                    break;
                }
            }
            return res;
        }
    };
    

    方法二:使用哈希表存储索引

    我们可以对方法一进行修改,使得第二次遍历的对象从字符串变为哈希映射。

    具体地,对于哈希映射中的每一个键值对,键表示一个字符,值表示它的首次出现的索引(如果该字符只出现一次)或者 −1(如果该字符出现多次)。当我们第一次遍历字符串时,设当前遍历到的字符为 c,如果 c 不在哈希映射中,我们就将 c 与它的索引作为一个键值对加入哈希映射中,否则我们将 c 在哈希映射中对应的值修改为 −1。

    在第一次遍历结束后,我们只需要再遍历一次哈希映射中的所有值,找出其中不为 −1 的最小值,即为第一个不重复字符的索引,然后返回该索引对应的字符。如果哈希映射中的所有值均为 −1,我们就返回空格。

    class Solution {
    public:
        char firstUniqChar(string s) {
            int n = s.size();
            unordered_map<char, int> mp;
            for (int i = 0; i < n; i++)
                if (mp.count(s[i]))
                    mp[s[i]] = -1;
                else 
                    mp[s[i]] = i;
            
            int minIndex = n;
            for (auto [c, index] : mp)
                if (index != -1 && index < minIndex)
                    minIndex = index;
            
            return minIndex == n ? ' ' : s[minIndex];
        }
    };
    

    方法三:队列

    我们也可以借助队列找到第一个不重复的字符。队列具有「先进先出」的性质,因此很适合用来找出第一个满足某个条件的元素

    具体地,我们使用与方法二相同的哈希映射,并且使用一个额外的队列,按照顺序存储每一个字符以及它们第一次出现的位置。当我们对字符串进行遍历时,设当前遍历到的字符为 c,如果 c 不在哈希映射中,我们就将 c 与它的索引作为一个二元组放入队尾,否则我们就需要检查队列中的元素是否都满足「只出现一次」的要求,即我们不断地根据哈希映射中存储的值(是否为 −1)选择弹出队首的元素,直到队首元素「真的」只出现了一次或者队列为空。

    在遍历完成后,如果队列为空,说明没有不重复的字符,返回空格,否则队首的元素即为第一个不重复的字符以及其索引的二元组。

    在维护队列时,我们使用了「延迟删除」这一技巧。也就是说,即使队列中有一些字符出现了超过一次,但它只要不位于队首,那么就不会对答案造成影响,我们也就可以不用去删除它。只有当它前面的所有字符被移出队列,它成为队首时,我们才需要将它移除。

    class Solution {
    public:
        char firstUniqChar(string s) {
            int n = s.size();
            unordered_map<char, int> mp;
            queue<char> q;
            
            for (int i = 0; i < n; i++) {
                if (mp.count(s[i])) {
                    mp[s[i]] = -1;
                    while (q.size() && mp[q.front()] == -1)
                        q.pop();
                } else {
                    mp[s[i]] = i;
                    q.push(s[i]);
                }
            }
            
            return q.size() ? q.front() : ' ';
        }
    };
    
    class Solution {
    public:
        char firstUniqChar(string s) {
            int n = s.size();
            unordered_map<char, int> mp;
            queue<char> q;
            
            for (int i = 0; i < n; i++) {
                mp[s[i]]++;
                if (mp[s[i]] > 1) {
                    while (q.size() && mp[q.front()] > 1)
                        q.pop();
                } else {
                    q.push(s[i]);
                }
            }
            
            return q.size() ? q.front() : ' ';
        }
    };
    
  • 相关阅读:
    【codecombat】 试玩全攻略 第二章 边远地区的森林 一步错
    【codecombat】 试玩全攻略 第十八关 最后的kithman族
    【codecombat】 试玩全攻略 第二章 边远地区的森林 woodlang cubbies
    【codecombat】 试玩全攻略 第二章 边远地区的森林 羊肠小道
    【codecombat】 试玩全攻略 第十七关 混乱的梦境
    【codecombat】 试玩全攻略 第二章 边远地区的森林 林中的死亡回避
    【codecombat】 试玩全攻略 特别关:kithguard斗殴
    【codecombat】 试玩全攻略 第二章 边远地区的森林 森林保卫战
    【codecombat】 试玩全攻略 第二章 边远地区的森林
    实验3 类和对象||
  • 原文地址:https://www.cnblogs.com/fxh0707/p/15084787.html
Copyright © 2011-2022 走看看