• 牛客网剑指offer第34题——找到第一个只出现一次的字符


    题目如下:

    在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

    先上代码:

     1 class Solution {
     2 public:
     3     int FirstNotRepeatingChar(string str) {
     4         //冷静的思考这个个题目,明显我们需要完整的遍历完整个字符串才可以
     5        int length = str.size();
     6         if(length == 0)
     7             return -1;
     8         vector<int>cnt(52,0);//初始化所有字母的统计为0;
     9         for(int i = 0;i < length;i++)
    10         {
    11             if(str[i] <= 90)
    12                 cnt[str[i]-65]++;
    13             else
    14                 cnt[str[i]-65-6]++;
    15         }
    16         for(int i = 0;i <length;i++)
    17            {
    18            if(str[i] <= 90)
    19            {
    20              if(cnt[str[i]-65] == 1)
    21                 return i;
    22            }
    23            else 
    24            {
    25                if(cnt[str[i]-65-6] == 1)
    26                    return i;
    27            }
    28         }
    29         return -1;
    30     }
    31 };

    这个问题的思路是什么?

    我知道很多人要说一看就是hash,抱歉说实话,我之前学习过hash,但现在还不知道怎么用。但是并不妨碍我做这一道题!

    首先,题目说找到第一个只出现一次的字符,这说明了什么?

    试想?如果你不遍历完整个字符串,你知道第一个只出现一次的字符是什么吗?答案是无法知道的。这也就断了你用其他高超技巧的念头,也就是说如果你不遍历完,那么你根本无法得知。

    因此,我们需要做的首先就是遍历完所有的字符。

    题目中说了只有大写和小写字母,那么我们可以申请一个最小为26*2的空间大小的数组(上文已经说了你跟本不知道有哪些字符要出现,所以你必须至少申请这么多!)

    然后我们要做什么?

    当然事统计每个字符出现的频数。

    我们的想法很简单,让A-Z对应vector的索引0-25,让a-z对应索引26-51。也就是对应索引位置的值为该字符出现的次数,比如cnt[0]表示字符A出现的次数。

    也就是下面这段代码:

    1  for(int i = 0;i < length;i++)
    2         {
    3             if(str[i] <= 90)
    4                 cnt[str[i]-65]++;
    5             else
    6                 cnt[str[i]-65-6]++;
    7         }

    当我们统计完之后,就应该查找了,说实话,我做完了这一步并不知道怎么找第一个,并一度认为这样的做法无法找出第一个出现一次的字符。为何我会这么认为呢?这里描述一下我开始的思维过程:

    比如 f和a都出现了一次,但是f先出现,a后出现,所以正确的结果中应该返回f的位置。但是我当时想:这个统计数组是按照字母表排序的,如果我按照数组cnt查找第一个,那么第一个cnt==1的必然是a,那么我当然会去原字符串中去找a所在的位置。那么此时返回的结果并不是第一次只出现一次的字符,而是只出现一次的字符在字母表中的第一个。这个结果当然是错误的。究其原因,是因为我们试图以数组cnt作为索引。去遍历cnt。

    但是实际上呢?我们可以不这么做,我们应该以原字符串为索引。也就是以原字符串的字符为key,而已cnt的值为value。这样才能得到正确的结果:

     1 for(int i = 0;i <length;i++)
     2            {
     3            if(str[i] <= 90)
     4            {
     5              if(cnt[str[i]-65] == 1)
     6                 return i;
     7            }
     8            else 
     9            {
    10                if(cnt[str[i]-65-6] == 1)
    11                    return i;
    12            }
    13         }

    我们可以看到第五行和第十行的代码,明显是以字符为索引,以cnt为value,这样便得到了正确的结果。

    倘若我们以cnt为key,str为value。显然是得不到正确结论的

  • 相关阅读:
    vue 底层面试题
    js第二阶段的面试题
    vue新一轮的面试题
    vue3面试题
    day_33:后端day04Django框架中的视图和请求、响应
    day_37:后端day08Django框架前后端不分离模式实现项目管理系统(增删差改)
    day_36:后端day07Django框架中的ORM数据库操作二
    【漏洞复现】ThinkAdmin v5和v6 未授权列目录任意文件读取(CVE202025540)
    【超详细】安全测试===sqlmap使用心得(零)
    【最新】绕过Outlook 拦截钓鱼链接方式
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/12443383.html
Copyright © 2020-2023  润新知