• 剑指Offer对答如流系列


    面试题50:字符串中第一个只出现一次的字符

    题目描述

    (1)在字符串中找出第一个只出现一次的字符。

    如输入"abaccdeff",则输出'b'。

    (2)字符流中第一个只出现一次的字符

    请实现一个函数,用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是'g'。当从该字符流中读出前六个字符"google"时,第一个只出现一次的字符是'l'

    问题分析

    问题(1):

    可以看出来,我们需要记录字符出现的次数,这个时候很容易联想到hash表

    由于字符(char)是长度为8位的数据类型,共有256中可能,可以利用字符的ASCII和字符出现的次数凑成 键值对。考虑是数字的形式,我们采用数组。

    创建以数组为数据结构的哈希表,键值key为字符的ASCII值,值value为出现次数。第一遍扫描:对每个扫描到的字符的次数加一;第二遍扫描:对每个扫描到的字符通过哈希表查询次数,第一个次数为1的字符即为符合要求的输出。

    问题(2)

    字符只能一个一个从字符流中读出来,很容易要定义一个容器来保存字符以及其在字符流中的位置。(我们接触过数据流的习题剑指Offer对答如流系列 - 数据流中的中位数

    同样,这个数据容器可以用哈希表来实现,以字符的ASCII码作为哈希表的键值key,字符对应的位置作为哈希表的值value。

    1. 开始时,哈希表的值都初始化为-1,当读取到某个字符时,将位置存入value中

    2. 如果之前读取过该字符(即value>=0),将value赋值为-2,代表重复出现过。

    3. 最后对哈希表遍历,在value>=0的键值对中找到最小的value,该value即为第一个只出现一次的字符,ASCII码为key的字符即为所求字符。

    小总结

    结合 前面见到的习题,希望你能有这个意识:数据流、字符流等,需要定义数据容器来保存记录。并能流和串的区别:

    1. 串:字符串已经保存下来了,能够读取遍历,因此在字符串中第一个只出现一次的字符中,只需要存下每个字符出现的个数,然后直接在字符串中遍历;

    2. 流:字符流没有存下来,无法进行遍历,因此在本题中,只能在数据容器哈希表中遍历,而且哈希表中存放的是对应字符的位置,而不是个数。

    在脑海中对 字符与ASCII码的转化,以及 字符形式的数字转和整型数字间的转化 有个比较清晰的认识

        //字符转化为ASCII码
        char ch_a = 'a';
        int code_a = (int)ch_a; // =ASCII码97
         
        //ASCII码转化为字符
        char copyCh_a = (char) code_a;  // =ASCII码97对应的字符'a'
         
        //字符形式数字转化为整型
        char c1 = '2';
        int n1 = c1-'0';  //=2, 由'2'和'1'的ASCII码相减得到
         
        //数字转化为字符形式
        char copyC1 = (char)(n1+'0');  //='2' ,由'0'的ASCII码加2得到'2'的ASCII码
    

    问题解答

    问题(1)

      public char firstNotRepeatingChar(String str) {
            if(str==null) {
                return '';
            }
            int[] repetitions = new int[256];
            Arrays.fill(repetitions, 0);
            for(int i=0;i<str.length();i++) {
                int loc= str.charAt(i);
                repetitions[loc]+=1;
            }
            for(int i=0;i<str.length();i++) {
                int loc= str.charAt(i);
                if(repetitions[loc]==1)
                    return (char)loc;
            }
            return '';
        }
    

    问题(2)

    public class FirstCharacterInStream {
    
        private int index;
        private int[] occurence;
    
        public FirstCharacterInStream() {  //在构造函数中初始化成员变量
            index=0;
            occurence = new int[256];
            Arrays.fill(occurence, -1);
        }
    
        public void insert(char ch) {
            if(occurence[(int)ch]==-1) {
                // 第一次出现
                occurence[(int)ch]=index;
            } else if(occurence[(int)ch]>=0) {
                // 已经出现过了
                occurence[(int)ch]=-2;
            }
            index++;
        }
    
        public char getFirst() {
            int minIndex=Integer.MAX_VALUE;  //最大的integer
            char ch='#';
            for(int i=0;i<256;i++) {
                if(occurence[i]>=0 && occurence[i]<minIndex) {
                    ch = (char) i;
                    minIndex=occurence[i];
                }
            }
            return ch;
        }
    }
    
  • 相关阅读:
    【欧拉函数】BZOJ2190-[SDOI2012]longge的数学问题
    【AC自动机+DP】USACO2012 JAN GOLD_Video Game Combos
    【斜率优化】BZOJ1010 [HNOI2008]玩具装箱toy
    【二维单调队列】BZOJ1047-[HAOI2007]理想的正方形
    【单调队列优化DP】BZOJ1855-[Scoi2010]股票交易
    [Usaco2008 Open]Word Power 名字的能量
    bzoj 1623: [Usaco2008 Open]Cow Cars 奶牛飞车
    bzoj 3479: [Usaco2014 Mar]Watering the Fields
    1163: [Baltic2008]Mafia
    [HAOI2007]反素数ant
  • 原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246539.html
Copyright © 2020-2023  润新知