剑指offer(50-第一个只出现一次的字符) 题解

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

微信搜索【程序员画工师】关注更多Java编程技术、数据结构与算法、面试题相关内容。

题目

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

思路1

最直观的想法是从头开始扫描这个字符串中的每个字符。当访问到某字符时拿这个字符和后面的每个字符相比较,如果在后面没有发现重复的字符,则该字符就是只出现一次的字符。
如果字符串有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路的时间复杂度是O(n2)。 
为了优化时间效率,我们可以定义一个哈希表(外部空间),其键值(Key)是字符,而值(Value)是该字符出现的次数。  
同时我们还需要从头开始扫描字符串两次:  
(1)第一次扫描字符串时,每扫描到一个字符就在哈希表的对应项中把次数加1。(时间效率O(n))   
(2)第二次扫描时,每扫描到一个字符就能从哈希表中得到该字符出现的次数。这样第一个只出现一次的字符就是符合要求的输出。(时间效率O(n))
  这样算起来,总的时间复杂度仍然是O(n)

上代码

import java.util.HashMap;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        HashMap<String,Integer> map = new HashMap<String,Integer>();
        String s = "";
        for(int i = 0;i < str.length(); i++){
            s = str.charAt(i) + "";
            if(map.containsKey(s))
            {
                map.put(s, 2);
            }
            else {
                map.put(s, 1);
            }
        }
        for(int i = 0;i < str.length(); i++){
            s = str.charAt(i) + "";
            if(map.get(s) == 1)
            {
                return i;
            }
        }
        return -1;
    }
}

思路2

字符(char)是一个长度为8的数据类型,因此总共有256种可能。这里我们只列举char是1个字节的情况,我们创建一个长度为256的数组来模拟哈希表,每个字母根据其ASCII码值作为数组的下标对应数组的一个数字,而数组中存储的是每个字符出现的次数。计算下来,它的大小是256*4字节(1个int类型在Windows下占4个字节)=1K。由于这个数组的大小是个常数,因此可以认为这种算法的空间复杂度是O(1)。

上代码

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        int[] numCount = new int[256];
        for(int i = 0;i < str.length(); i++){
            numCount[str.charAt(i)]++;
        }
        for(int i = 0;i < str.length(); i++){
            if(numCount[str.charAt(i)] == 1){
                return i;
            }
        }
        return -1;
    }
}

举一反三

如果需要判断多个字符是不是在某个字符串里出现过或者统计多个字符在某个字符串中出现的次数,那么我们可以考虑基于数组创建一个简单的哈希表,这样可以用很小的空间消耗来获取效率的提升。

References

[1] 《剑指offer(第二版)》 何海涛著

程序员画工师公众号,获取更多详细Java、Python、C、前端、小程序、产品相关学习资料,欢迎交流
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值