题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

分析:这是一道广为流传的面试题,包括百度、微软和Google在内的多家公司都曾经采用过这个题目。要几十分钟的时间里很好地解答这道题,除了较好的编程能力之外,还需要较快的反应和较强的逻辑思维能力。

看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)。

接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。本博客系列的第13题就是一个应用哈希表的例子。不过本题并没有限制数组里数字的范围,我们要么需要创建一个很大的哈希表,要么需要设计一个很复杂的方法来计算哈希值。因此总体说来这个方法还不是很好。

前面两种思路都没有考虑到题目中数组的特性:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。

基于这个思路,我们不难写出如下代码:

bool g_bInputInvalid = false;//
// Input: an array with "length" numbers. A number in the array
// appear more than "length / 2 + 1" times.
// Output: If the input is valid, return the number appearing more than
// "length / 2 + 1" times. Otherwise, return 0 and set flag g_bInputInvalid
// to be true.
//
int MoreThanHalfNum(int* numbers, unsigned int length)
{if(numbers == NULL && length == 0){g_bInputInvalid = true;return 0;}g_bInputInvalid = false;int result = numbers[0];int times = 1;for(int i = 1; i < length; ++i){if(times == 0){result = numbers[i];times = 1;}else if(numbers[i] == result)times++;elsetimes--;}// verify whether the input is validtimes = 0;for(int i = 0; i < length; ++i){if(numbers[i] == result)times++;}if(times * 2 <= length){g_bInputInvalid = true;result = 0;}return result;
}

在上述代码中,有两点值得讨论:

(1)      我们需要考虑当输入的数组或者长度无效时,如何告诉函数的调用者输入无效。关于处理无效输入的几种常用方法,在本博客系列的第17题中有详细的讨论;

(2)      本算法的前提是输入的数组中的确包含一个出现次数超过数组长度一半的数字。如果数组中并不包含这么一个数字,那么输入也是无效的。因此在函数结束前我还加了一段代码来验证输入是不是有效的。

本文已经收录到《剑指Offer——名企面试官精讲典型编程题》一书中,有改动,书中的分析讲解更加详细。欢迎关注。

本题已被九度Online Judge系统收录,欢迎读者移步到http://ac.jobdu.com/hhtproblems.php在线测试自己的代码。

博主何海涛对本博客文章享有版权。网络转载请注明出处http://zhedahht.blog.163.com/。整理出版物请和作者联系。对解题思路有任何建议,欢迎在评论中告知,或者加我微博http://weibo.com/zhedahht或者http://t.163.com/zhedahht与我讨论。谢谢。

程序员面试题精选100题(47)-数组中出现次数超过一半的数字[算法]相关推荐

  1. 程序员面试题精选100题(34)-数组中只出现一次的数字[算法]

    题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 分析:这是一道很新颖的关于位运算的面试题. 首先我们 ...

  2. 程序员面试题精选100题(63)-数组中三个只出现一次的数字[算法]

    题目:一个数组中有三个数字a.b.c只出现一次,其他数字都出现了两次.请找出三个只出现一次的数字. 分析:在博客http://zhedahht.blog.163.com/blog/static/254 ...

  3. 程序员面试题精选100题:41-50解题报告

    程序员面试题精选100题(41)-把数组排成最小的数[算法]   题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32,  321},则输出这两个能 ...

  4. 程序员面试题精选100题(05)-查找最小的k个元素[算法]

    题目:输入n个整数,输出其中最小的k个. 例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 分析:这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个 ...

  5. 程序员面试题精选100题(38)-输出1到最大的N位数[算法]

    题目:输入数字n,按顺序输出从1最大的n位10进制数.比如输入3,则输出1.2.3一直到最大的3位数即999. 分析:这是一道很有意思的题目.看起来很简单,其实里面却有不少的玄机. 应聘者在解决这个问 ...

  6. 程序员面试题精选100题(46)-对称子字符串的最大长度[算法]

    题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度.比如输入字符串"google",由于该字符串里最长的对称子字符串是"goog",因此输出4. 分析 ...

  7. 程序员面试题精选100题

    程序员面试题精选100题(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 比如将二元查找树   ...

  8. [程序员面试题精选100题]13.第一个只出现一次的字符

    [题目] 在一个字符串中找到第一个只出现一次的字符.如输入abaccdeff,则输出b. [分析] [代码] /********************************* * 日期:2013- ...

  9. 程序员面试题精选100题(51)-顺时针打印矩阵

    // 程序员面试题精选100题(51)-顺时针打印矩阵.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <iostre ...

最新文章

  1. c++中类的定义与头文件的关系
  2. Golang 日志框架 Zap 入坑指南
  3. 目前在线教育发展情况介绍
  4. 认识Python(day01)
  5. Webpack - 自学笔记
  6. LeetCode题库整理【Java】—— 1两数之和
  7. 多线程编程进阶——Java类库中的锁
  8. mysql获取多张表中的数据_mysql之多表查询
  9. wineskin下plsql解决中文乱码问题
  10. python DEA: 非径向距离函数(non-radial directional distance function)
  11. python数据科学导论_R与Python手牵手:数据科学导论系列(包的载入)
  12. 在Ubuntu系统上安装minidwep-gtk软件
  13. 世界著名激励大师约翰·库缇斯的传奇人生
  14. 算法设计与分析 ——10-7课程总结
  15. Alink(1):Alink概述
  16. tweak环境安装及编写
  17. 风口上的猪-中国牛市
  18. pyspider 文档介绍
  19. 安卓机调用 audio.play()时 报错:API can only be initiated by a user gesture
  20. Are These Birds?

热门文章

  1. Day 4 - PB级规模数据的Elasticsearch分库分表实践
  2. Inchat时代真的来了?上线一周突破百万用户
  3. Oracle优化07-分析及动态采样-直方图
  4. HTML内嵌式CSS背景图填充满无截断重复
  5. 杜克大学计算机科学专业,杜克大学计算机科学专业研究生留学申请条件高不高?...
  6. Qt 设置窗口背景图片的几种方法
  7. centos 更换java版本_centos7更换jdk版本
  8. linux文件历史,Linux文件系统的历史透视
  9. android 两个竖排listview,Android布局 – 在ListView行内垂直堆叠两个TextView
  10. MATLAB-字符串