• 剑指 Offer 50. 第一个只出现一次的字符



    本题 题目链接

    题目描述


    我的题解

    (方法三应用更广泛;方法一虽有限制,但很好用,此题中该方法效率也最高)

    方法一:(适用于范围确定的)

    思路分析

    • 该字符串只包含小写字母,即字符种类最多26个
    • 开一个数组yes[26],分别存放字母a-z所出现的次数。
    • 字符c对应的数组下标索引为为:c-97.
    • 我的代码中,为了节约空间,取的是byte类型数组:
      • 当某个字符出现次数<2,该字符对应的数组值+1;
      • 否则(即出现次数>=2,不符合题目要找的),不处理该字符对应的数组值(即不再+1,因为byte类型最大值为127,而题目数据可能出现某个字符出现次数多达50000的情况)。

    代码如下

        public char firstUniqChar(String s) {
            char[] chars = s.toCharArray();
            byte[] yes = new byte[26];
            for (char c : chars) {
                if (yes[c-97]<2)yes[c-97]++;
            }
            char res = ' ';
            for (char c : chars) {
                if (yes[c-97]==1) {
                    res = c;
                    break;
                }
            }
            return res;
        }
    

    方法二:哈希表

    方法二的优化 是参考leetcode大佬的题解。大佬leetcode主页

    思路分析

    • 创建一个哈希表:HashMap<Character, Boolean> dic。
    • 遍历字符串s 中的每个字符 c:
      • 若字符c第一次出现,则向dic中添加键值对:dic.put(c, true);
      • 若前面已经出现过,则修改键c的键值对:dic.put(c, false) 【字符c数量大于1,不符合题目要找的】;

    代码如下:

        public char firstUniqChar(String s) {
            Map<Character, Boolean> dic = new HashMap<>();
            char[] chars = s.toCharArray();
    
            for (char c : chars) {  // 遍历字符串
                dic.put(c, !dic.containsKey(c)); // 若dic中不包含键 c :则向dic中添加键值对 (c, True) ;
                                                // 若包含键 c :则修改键c的键值对为 (c, False)。
            }
            char res = ' ';
            // 再次遍历字符串s,查看哈希表中键 c对应的value值,找出第一个true
            for (char c : chars) {
                if (dic.get(c)) {
                    res = c;
                    break;
                }
            }
            return res;
        }
    
    

    方法三:有序哈希表

    方法三 是参考leetcode大佬的题解。大佬leetcode主页

    思路分析

    • 在哈希表的基础上,有序哈希表中的键值对是 按照插入顺序排序 的。
    • 故在方法二的基础上, 对于数据量大的题目,方法三效率更高。
    • 方法二中,第二个for循环,遍历的是字符串s;而方法三中第二个for循环只需遍历有序哈希表即可(因哈希表是去重的,故减少了循环的次数,增加了效率)

    代码如下

        public char firstUniqChar(String s) {
            Map<Character, Boolean> dic = new LinkedHashMap<>();
            char[] chars = s.toCharArray();
    
            for (char c : chars) {
                dic.put(c, !dic.containsKey(c)); // 若dic中不包含键 c :则向dic中添加键值对 (c, True) ;
                                                // 若包含键 c :则修改键c的键值对为 (c, False)。
            }
    
            for (Map.Entry<Character, Boolean> entry : dic.entrySet()) {
                if (entry.getValue()) return entry.getKey();
            }
            return ' ';
        }
    
    
  • 相关阅读:
    树链剖分总结
    主席树总结
    BZOJ1053:反素数(数学)
    CH3101 阶乘分解
    2018-2019 ACM-ICPC ECfinal I. Misunderstood … Missing
    洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
    Codeforces Round #552 (Div. 3) 题解
    线段树合并 总结
    生成器
    Python中input()和raw_input()的区别
  • 原文地址:https://www.cnblogs.com/duduwy/p/13380135.html
Copyright © 2020-2023  润新知