[剑指offer学习心得]之:第一个只出现一次的字符

本文介绍了一种高效的算法,用于从字符串中找到第一个仅出现一次的字符。通过两次扫描和使用哈希表,该算法实现了O(n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串中找出第一个只出现一次的字符。比如说输入“abaccdeff“,则输出“b“。

最直观的想法是从头开始扫描这个字符串中的每个字符。当访问某个字符时拿这个字符和后面没个字符 做比较,如果在后面没有发现重复字符,则该字符就是要找的。如果字符串有n个字符,没个字符可能与后面O(n)个字符比较,所以这个思路的时间复杂度为O(n^2)。当然面试官时不会满意这种思路的,要换。

除此以外还可以统计每一个字符在该字符串中出现的次数。那么肯定就需要一个数据容器存放每隔字符的出现次数,而且在这个容器中可以根据字符来查找它出现的次数,就是说此容器的作用是把一个字符映射成一个数字,那么必然要使用到哈希表。

所以我们定义哈希表键值key是字符,值value是字符出现的次数。并且对字符串扫描两次:第一次每扫描到一个字符就在哈希表对应项中把次数加1;第二次每扫描到一个字符就能从哈希表中得到该字符出现的次数。那么第一个只出现一次的字符就是符合要求的输出了。

第一次扫描时,在哈希表中更新一个字符出现的次数的时间是 O(n) 。如果字符串长度为 n, 那么第一次扫描的时间复杂度是 O(n)。第二次扫描时,同样 0(1)能读出一个字符出现的次数,所以时间复杂度仍然是 O(n)。这样算起来,总的时间复杂度是 O(n)。

ok,清楚了这些思路之后就可以动手写代码了:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class FirstNotRepeatChar {

    public static void main(String[] args){
        System.out.println(firstNotRepeatChar("google"));
        System.out.println(firstNotRepeatChar("aabccdbd"));
        System.out.println(firstNotRepeatChar("abcdefg"));
        System.out.println(firstNotRepeatChar("gfedcba"));
        System.out.println(firstNotRepeatChar("zgfedvba"));
//      System.out.println(firstNotRepeatChar(null));
    }

    private static char firstNotRepeatChar(String s){
        if(s==null||s.length()<1){
            throw new IllegalArgumentException("Arg should not be null or empty");
        }
        /**
         * 第一次扫描:只记录只出现一次的字符的位置。其他的value都记为-2
         */
        Map<Character,Integer> map=new LinkedHashMap<Character,Integer>();
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(map.containsKey(c)){
                map.put(c, -2);//当出现一样的,当然就表示这个字符出现了两个或两个以上,可以直接置value为-2
            }else{
                map.put(c, i);//如果是第一次出现,那么记录下位置
            }
        }

        /**
         * 第二次扫描:找出第一个只出现一次的字符
         */
        Set<Map.Entry<Character,Integer>> entrySet=map.entrySet();
        //记录只出现一次的字符的索引
        int index=Integer.MAX_VALUE;
        //记录只出现一次的字符
        char result='\0';//初始化
        //找最小索引对应的字符
        for(Map.Entry<Character, Integer> entry:entrySet){
            if(entry.getValue()>=0&&entry.getValue()<index){
                index=entry.getValue();
                result=entry.getKey();
            }
        }
        return result;
    }
}

注意了,这里面的测试用例:

  1. 功能测试:字符串中存在只出现一次的字符,字符串中不存在只出现一次的字符,字符串中所有字符都只出现一次。

  2. 特殊输入测试:字符串为null。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值