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


    34. 第一个只出现一次的字符

    思路一:计数排序

    先使用计数排序统计每个字符出现的次数,然后再次遍历字符串,判断每个字符出现的次数,返回第一个次数为1的字符

    由于限定了所有字符为字母,所以可以统计每个字符出现的次数,然后第二次遍历字符串,判断每个字符出现的次数,找到第一个次数为一的返回即可

    这里计数数组长度设置为 58, 是因为 大写字符的 ASCII 范围为 65 - 90, 小写字符的ASCII 范围为 97 - 122,所以从 65 - 122 共58个单位长度

    public class Solution {
        public int FirstNotRepeatingChar(String str) {
            // 计数排序
            // 数组长度只需 58即可 112 - 65 + 1 = 58
            int[] count = new int[58];
            for(int i = 0; i < str.length(); i++){
                count[str.charAt(i) - 'A']++;
            }
           
            // 再次遍历 str 字符串,找到第一个字符对应的个数为1即可
            for(int i = 0; i < str.length(); i++){
                if(count[str.charAt(i) - 'A'] == 1){
                    return i;
                }
            }
            return -1;
        }
    }

    复杂度分析:

    时间复杂度:最多遍历两次字符串,所以时间复杂度为O(n)

    空间复杂度:借助了一个长度为58的数组,是常量级的,所以空间复杂度为O(1)

    注:

    Java 中的字符在于整数做加减运算的时候也会转换成 ASCII 来做运算,所以可以作为下标来使用。

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

    在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

    示例:

    s = "abaccdeff"
    返回 "b"
    
    
    s = "" 
    返回 " "

    思路一:同上思路一,使用计数排序实现

     1 class Solution {
     2     public char firstUniqChar(String s) {
     3         // 先使用计数排序统计每个字符出现的次数
     4         int[] counts = new int[26];
     5         int len = s.length();
     6         for(int i = 0; i < len; i++){
     7             counts[s.charAt(i) - 'a']++;
     8         }
     9 
    10         // 然后再次遍历字符串,判断每个字符出现的次数,返回第一个次数为1的字符
    11         for(int i = 0; i < len; i++){
    12             if(counts[s.charAt(i) - 'a'] == 1){
    13                 return s.charAt(i);
    14             }
    15         }
    16         
    17         return ' ';
    18     }
    19 }

    leetcode 运行时间为8ms, 空间为39.4MB

    复杂度分析:

    时间复杂度:最多遍历两次字符串,所以时间复杂度为O(2n)

    空间复杂度:需要一个大小为26的数组,但是大小时产量级的,所以空间复杂度为O(1)

    思路二:使用LinkedHashMap这个有序 hash表实现

    LinkedHashMap不仅可以统计出现次数,还可以维护一个插入顺序,所以减少了第二次扫描字符串的开销

     1 class Solution {
     2     public char firstUniqChar(String s) {
     3         // 先使用计数排序统计每个字符出现的次数
     4         LinkedHashMap<Character, Boolean> map = new LinkedHashMap<>();
     5         int len = s.length();
     6         for(int i = 0; i < len; i++){
     7             map.put(s.charAt(i), !map.containsKey(s.charAt(i)));    // 如果重复则置为false
     8         }
     9 
    10         // 遍历map,因为mp的大小最大为26, 所以这次循环的时间复杂度为O(1)
    11         for(Map.Entry<Character, Boolean> en : map.entrySet()){
    12             if(en.getValue() == true){
    13                 return en.getKey();
    14             }
    15         }
    16 
    17         return ' ';
    18     }
    19 }

    leetcode运行时间为:38ms, 时间为39.5MBb, 根据前面思路介绍的,案例来说这个时间应该比思路一快才对,但是事实就是慢这么多,我觉得应该是思路一用的是数组来计数,所以效率较高,但是如果使用hashmap来计数的话,那时间上应该会比当前解法慢

    复杂度分析:

    时间复杂度:遍历了一次字符串,花费时间为O(n), 虽然后面还是有一个遍历map的循环,但是循环次数最多为26次,可以忽略不计,所以总的时间复杂度为O(n)

    空间复杂度:借用了一个大小为26的 LinkedHashMap, 常量级别的,所以空间复杂度为O(1)

  • 相关阅读:
    POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)
    LCA 最近公共祖先 (模板)
    线段树,最大值查询位置
    带权并查集
    转负二进制
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/12599528.html
Copyright © 2020-2023  润新知