一、题目:第一个只出现一次的字符

题目:在字符串中找出第一个只出现一次的字符。如输入"abaccdeff",则输出'b'。要求时间复杂度为O(n)

  最直观的想法是从头开始扫描这个字符串中的每个字符。当访问到某字符时拿这个字符和后面的每个字符相比较,如果在后面没有发现重复的字符,则该字符就是只出现一次的字符。如果字符串有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路的时间复杂度是O(n2),但是不满足要求。

二、解题思路:以空间换时间

  为了解决这个问题,我们可以定义一个哈希表(外部空间),其键值(Key)是字符,而值(Value)是该字符出现的次数。

  同时我们还需要从头开始扫描字符串两次:

  (1)第一次扫描字符串时,每扫描到一个字符就在哈希表的对应项中把次数加1。(时间效率O(n))

  (2)第二次扫描时,每扫描到一个字符就能从哈希表中得到该字符出现的次数。这样第一个只出现一次的字符就是符合要求的输出。(时间效率O(n))

  这样算起来,总的时间复杂度仍然是O(n),满足了题目要求,擦一擦汗,感叹:这*装得真有点技术!

  装完了B,开始将这个想法实现为代码:

    public static char FirstNotRepeatingChar(string str)
{
if(string.IsNullOrEmpty(str))
{
return '\0';
} char[] array = str.ToCharArray();
const int size = ;
// 借助数组来模拟哈希表,只用1K的空间消耗
uint[] hastTable = new uint[size];
// 初始化数组
for (int i = ; i < size; i++)
{
hastTable[i] = ;
} for (int i = ; i < array.Length; i++)
{
hastTable[array[i]]++;
} for (int i = ; i < array.Length; i++)
{
if (hastTable[array[i]] == )
{
return array[i];
}
} return '\0';
}

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

三、单元测试

3.1 测试用例

    // 常规输入测试,存在只出现一次的字符
[TestMethod]
public void FirstCharTest1()
{
char actual = CharHelper.FirstNotRepeatingChar("google");
Assert.AreEqual(actual, 'l');
} // 常规输入测试,不存在只出现一次的字符
[TestMethod]
public void FirstCharTest2()
{
char actual = CharHelper.FirstNotRepeatingChar("aabccdbd");
Assert.AreEqual(actual, '\0');
} // 常规输入测试,所有字符都只出现一次
[TestMethod]
public void FirstCharTest3()
{
char actual = CharHelper.FirstNotRepeatingChar("abcdefg");
Assert.AreEqual(actual, 'a');
} // 鲁棒性测试,输入NULL
[TestMethod]
public void FirstCharTest4()
{
char actual = CharHelper.FirstNotRepeatingChar(null);
Assert.AreEqual(actual, '\0');
}

3.2 测试结果

  (1)测试通过情况

  (2)代码覆盖率

四、总结扩展

  如果需要判断多个字符是不是在某个字符串里出现过或者统计多个字符在某个字符串中出现的次数,我们都可以考虑基于数组创建一个简单的哈希表(或者使用基类库中提供的现成的哈希表结构类型)。这样可以用很小的空间消耗换来换取时间效率的提升。

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

剑指Offer面试题:30.第一个只出现一次的字符的更多相关文章

  1. 剑指Offer - 九度1283 - 第一个只出现一次的字符

    剑指Offer - 九度1283 - 第一个只出现一次的字符2013-11-21 21:13 题目描述: 在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出 ...

  2. 【Java】 剑指offer(50-1) 字符串中第一个只出现一次的字符

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在字符串中找出第一个只出现一次的字符.如输入"abacc ...

  3. 剑指offer(34)第一个只出现一次的字符

    题目描述 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置 题目分析 只需要用map记录字符出现的次数就行,比较简单的题 代码 f ...

  4. 【剑指Offer】34、第一个只出现一次的字符

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

  5. 剑指offer——面试题30:包含min函数的栈

    #include"iostream" #include"stdio.h" using namespace std; ; ; template<typena ...

  6. 剑指Offer:面试题30——最小的k个数(java实现)

    问题描述: 输入n个整数,找出其中最小的k个数 思路1: 先排序,再取前k个 时间复杂度O(nlogn) 下面给出快排序的代码(基于下面Partition函数的方法) public void Quic ...

  7. 剑指offer面试题30:最小的k个数

    一.题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 二.解题思路 1.思路1 首先对数组进行排序,然后取出前k个数 ...

  8. 剑指offer面试题30.包含min函数的栈

    一开始写的垃圾代码,push和pop都是O(N) class Solution { public: vector<int> vec; int min_val=INT_MAX,min_cnt ...

  9. 剑指offer 面试题56. 数组中只出现一次的两个数字

    题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 方法1:用set记录出现过的数字 class Solution { public: void F ...

  10. C++版 - 剑指offer之面试题37:两个链表的第一个公共结点[LeetCode 160] 解题报告

    剑指offer之面试题37 两个链表的第一个公共结点 提交网址: http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?t ...

随机推荐

  1. css sprite,css雪碧图生成工具V3.0更新

    V3.0主要改进 1.增加了单独添加单张图片以及删除单张图片的功能 2.增加了生成.sprite文件用以保存雪碧图信息 3.增加了打开.sprite文件功能 什么是css sprite CSS spr ...

  2. C#创建文件夹,往里追字符串。

    /// <summary>写文本日志</summary> /// <param name="StrMessage">日志消息</param ...

  3. persistence.xml文件的妙处

    在上家公司,经常要做的一个很麻烦的事就是写sql脚本, 修改了表结构,比如增加一个新字段的时候,都必须要写sql并放入指定目录中, 目的就是为了便于当我们把代码迁移到其他数据库中的时候,再来执行这些s ...

  4. windows下指定格式文件转移

    #放在目录下执行 1.bat 作用:将该目录下所有mp4格式的文件转移至该目录下的target目录下 须保证target目录不存在@echo off md target\ for /f "d ...

  5. js中的 || 与 && 运算符 的使用

    &&和||总是傻傻分不清,在这里详细记录一下吧.也给你们分享一下. 表达式a && 表达式b :  计算表达式(或者函数)a的运算结果, 如果为 True, 执行表达式 ...

  6. mysql索引总结----mysql 索引类型以及创建

    文章归属:http://feiyan.info/16.html,我想自己去写了,但是发现此君总结的非常详细.直接搬过来了 关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基 ...

  7. 国外程序员整理的Java资源大全分享

    Java 几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员 Andreas Kull 在其 Github 上整理了非常优秀的 Java 开发资源,推荐给大家. 译文由 Imp ...

  8. XVII Open Cup named after E.V. Pankratiev. GP of SPb

    A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using ...

  9. 2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)

    A. Arranging Hat $f[i][j]$表示保证前$i$个数字有序,修改了$j$次时第$i$个数字的最小值. 时间复杂度$O(n^3m)$. #include <bits/stdc+ ...

  10. js中自定义构造函数讲解

    什么是构造函数? 构造函数其实就是一个函数,只是用途和普通函数,不太一样, 构造函数一般用于初始化对象 <script> function Person(){ this.name=&quo ...