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)