剑指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)

 

posted @ 2020-03-30 16:46  Lucky小黄人^_^  阅读(122)  评论(0编辑  收藏  举报