剑指offer-第一个只出现一次的字符

题目描述

  • 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
  • 地址: 牛客链接

问题分析

  • 这题第一眼看到是用HashMap统计每个字符出现的次数,因为考虑到HashMap存储的无序性,value还要存储该字符(key)最后一次出现的位置,然后遍历map,找到出现1次的字符中出现位置最早的那一个。初始想法实在是蠢到家了。
  • 首先,可以用LinkedHashMap的存取有序性来做,因为它的底层实现是双向链表,这样先遍历一次,统计次数,然后再遍历一次,找到第一个出现次数为1(value = 1)的字符
  • 上面两个方法都是死脑筋!!!用hashmap统计完次数,为什么要用遍历map的方法去找呢,即使hashmap存取具有无序性,但如果按照字符串中字符出现的方式去找,那么自然而然,遇到的第一个出现次数为1的字符即为所求。
  • 此外,因为该字符串中只有大小写字母,那么也可以自己定制一个hash表啊,底层是数组。用字符的Asccic码作为hash值,也就是数组的index,这样比hashmap要节省效率。
    • 因为Ascii码是 0~255,所以可以定义一个长度256的数组,index为该字符的Asccic码,值为出现次数
    • 因为该字符串中只有大小写字母,A-Z对应的ASCII码为65-90,a-z对应的ASCII码值为97-122,所以可以将每个字母的index=int(word)-65,这是一个长度为58的数组,更加节省空间

经验教训

  • 千万别死脑筋!!!
  • HashMap的无序性与LinkedHashMap的有序性
  • 对于单个字符,可以用数组起到map的效果,字符的Ascii码作为数组的index。

代码实现

  • 初始死脑筋想法

    public int FirstNotRepeatingChar(String str) {
        int length = str.length();
        if (str == null || length == 0) {
            return -1;
        }
        if (length == 1) {
            return 0;
        }
        HashMap<Character, CountInfo> map = new HashMap<>();
        for (int i = 0; i < length; i++) {
            char ch = str.charAt(i);
            if (map.containsKey(ch)) {
                map.put(ch, new CountInfo(map.get(ch).count + 1 ,i));
            }else {
                map.put(ch, new CountInfo(1 ,i));
            }
        }
        int resIndex = length;
        for (Object o: map.keySet()) {
            CountInfo info = map.get(o);
            if (info.count == 1) {
                resIndex = Math.min(resIndex, info.index);
            }
        }
        return resIndex;
    }

    public class CountInfo{
        int count;
        int index;

        public CountInfo(int count, int index) {
            this.count = count;
            this.index = index;
        }
  • HashMap
    public int FirstNotRepeatingChar(String str) {
        int length = str.length();
        if (str == null || length == 0) {
            return -1;
        }
        if (length == 1) {
            return 0;
        }
        HashMap<Character,Integer> map = new HashMap<>();
        for (int i = 0; i < length; i++) {
            char ch = str.charAt(i);
            if (map.containsKey(ch)) {
                map.put(ch, map.get(ch) + 1);
            }else {
                map.put(ch, 1);
            }
        }
        for (int i = 0; i < length; i++) {
            if(map.get(str.charAt(i)) == 1) {
                return i;
            }
        }
        return -1;
    }
  • 数组实现hash表
     public int FirstNotRepeatingChar(String str) {
         int length = str.length();
         if (str == null || length == 0) {
             return -1;
         }
         if (length == 1) {
             return 0;
         }
         int[] map = new int[256];
         for (int i = 0; i < length; i++) {
             map[str.charAt(i)] += 1;
         }
         for (int i = 0; i < length; i++) {
             if (map[str.charAt(i)] == 1) {
                 return i;
             }
         }
         return -1;
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值