题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

分析思路:
      如果这个题目是排好序的数组,那么我们就很容易统计出每个数字出现的次数。题目给出的数组没有说是排好序的,因此我们需要先给它排序。排序的时间复杂度是O(nlogn)。最直观的算法通常不是面试官满意的算法,我们需要找出更快的算法。
****其中一种思路是:基于Partition函数的O(n)算法
       我们回到题目本身分析,就会发现前面的思路并没有考虑到数组的特性:数组中有一个数字出现的次数超过了数组长度的一半。如果我把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组一半的数字。也就是说,这个数字就是统计学上的中位数,即长度为n的数组中第n/2的数字。我们有成熟的O(n)的算法得到数组中任意第K大的数字。

       这种算法是受快速排序算法的启发。在随机快速排序算法中,我们现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小的数字都排在它的左边,比选中的数字大的数字都排在它的右边。如果这个选中的数字的下标刚好是n/2,那么这个数字就是数组的中位数。如果它的下标大于n/2,那么中位数应该位于它的左边,我们可以接着在它的左边部分的数组中查找。如果它的下标小于n/2,那么中位数应该位于它的右边,我们可以接着在它的右边部分的数组中查找。这是一个典型的递归过程,实现代码如下:

class Solution {
public:int MoreThanHalfNum_Solution(vector<int> numbers) {int length=numbers.size(); if(numbers.empty()||length<0)return 0;int middle=length>>1;int start=0;int end=length-1;//int index=partition(numbers,length,start,end);       int index=partition(numbers,start,end);               while(index!=middle){ if(index>middle){end=index-1;index=partition(numbers,start,end);  }else{start=index+1;index=partition(numbers,start,end);                }}int result=numbers[middle];           //这里的只是得到了第middle=n/2大的数字,但总个体是否超过一段还需要判断if(!CheckMoreThanHAlf(numbers,length,result))    //此时需要检查result的值的个数是否大于整个数组的一半return 0;return result;}int partition(vector<int> input,int low,int high){int pivotkey=input[low];   //pivot:枢纽//这里的pivotkey也可以是[low,high]区间一个随机数,也可以是三数取中,九数取中,详情见<<大话数据结构>>//int pivotkey=input[RandInRange(start,end)];while(low<high){while(low<high&&pivotkey<input[high])high--;swap(&input[low],&input[high]);while(low<high&&pivotkey>=input[low])low++;swap(&input[low],&input[high]);}  return low;}/*这个partition是优化了不必要的交换,将swap用赋值替换int partition(vector<int> &input, int begin, int end){int low = begin;int high = end;int pivot = input[low];while (low < high){while (low < high&&pivot <= input[high])high--;input[low] = input[high];         //优化不必要的替换while (low < high&&pivot >= input[low])low++;input[high] = input[low];         //优化不必要的替换}input[low] = pivot;return low;}*/bool CheckMoreThanHAlf(vector<int> numbers,int length,int result)    //检查result的值的个数是否大于整个数组的一半{int times=0;for(int i=0;i<length;++i){if(numbers[i]==result)times++;}bool isMoreThanHalf=true;if(times*2<=length)isMoreThanHalf=false;return isMoreThanHalf;}void swap(int *a,int *b)   //交换两个数{int temp;temp=*a;*a=*b;*b=temp;}/*下面的partition是剑指offer上的实现,考虑的很详情,但是没有上面的好理解int RandInRange(int a,int b)    //产生一个[a,b]范围内的随机整数{int c;c=a+rand()%(b-a+1);return c;}int partition(vector<int>& data,int length,int start,int end)    //partition函数是为了找出数组中第K大的数字 {if(data.empty()||length<0||start<0||end>=length)return 0;  //throw new std::exception("Invakid Parameters");int index=RandInRange(start,end);          swap(&data[index],&data[end]);   int small=start-1;for(index=start;index<end;++index){if(data[index]<data[end]){++small;if(small!=index)swap(&data[index],&data[small]); }}++small;swap(&data[small],&data[end]); return small;}*/
};

剑指offer面试题[29]-数组中出现次数超过一半的数字相关推荐

  1. 剑指offer面试题39. 数组中出现次数超过一半的数字(数组)(摩尔投票法)

    题目描述 **数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 你可以假设数组是非空的,并且给定的数组总是存在多数元素.** 思路 详见链接 代码 class Solution:def ...

  2. 【剑指offer-Java版】29数组中出现次数超过一半的数字

    数组中出现次数超过一半的数字 两种思路: 思路一:由于出现次数超过一半,所以如果对这个数组进行划分之后无论如何,位于数组下标 n/2的数字就是出现次数超过一半的数 所以问题就转换为了求划分一次之后 位 ...

  3. 【剑指Offer】28、数组中出现次数超过一半的数字

      题目描述:   数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.   例如:输入如下所示的一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过 ...

  4. 剑指offer:面试题39. 数组中出现次数超过一半的数字

    题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 你可以假设数组是非空的,并且给定的数组总是存在多数元素. 示例 1: 输入: [1, ...

  5. 剑指offer面试题[40]-数组中只出现一次的数字

    题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 注意原题目要求空间复杂度为0(1). 位运算的具体思路可以参看剑指offer. class So ...

  6. 剑指Offer - 面试题3. 数组中重复的数字(哈希)

    1. 题目 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组 ...

  7. 剑指offer 面试题03. 数组中重复的数字

    找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中任意一个重 ...

  8. 剑指offer面试题[36]-数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  9. 剑指offer面试题[51]-数组中重复的数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

最新文章

  1. mysql课程id数据类型_数据库学习之六:mysql数据类型
  2. 《Linux shell变量总结回顾》RHEL6
  3. toj 3711 水题
  4. 2.27 18种定位方法总结
  5. H5嵌入原生开发小结----兼容安卓与ios的填坑之路
  6. C语言查看队头元素,C语言实现循环队列的初始化进队出队读取队头元素判空-1...
  7. LeetCode 225. Implement Stack using Queues
  8. 安装Debian-9(Stretch)服务器图文教程
  9. lintcode:合并排序数组
  10. 理解node.js(Understanding node.js)
  11. 软件开发高手须掌握的4大SQL精髓语句(综合篇)
  12. android mount --bind挂载目录
  13. linux内存源码分析 - 内存回收(匿名页反向映射)
  14. 李宏毅机器学习笔记:机器学习介绍
  15. 如何用O2OA公文编辑器制作标准的红头文件?
  16. win7 共享计算机 网络密码怎么设置,win7局域网共享设置密码 win7局域网如何设置密码【详细步骤】...
  17. Ubuntu vsftp搭建和C# Winform FTP操作
  18. Linux如何删除用户
  19. 滑窗优化、边缘化、舒尔补、FEJ及fill-in问题
  20. Docker WordPress安装

热门文章

  1. win7下安装usb转串口不成功解决方法
  2. 101.接收上游响应的缓存处理流程
  3. python代码实现中心化_数据预处理——标准化(附python代码)
  4. 【论文写作】SSM房屋租赁系统如何写设计总结
  5. Android5手动root,魅蓝Note5如何获取ROOT权限?魅蓝Note5 ROOT教程(亲测可行)
  6. 进程与服务的签名_服务器被黑客攻击后如何查找溯源攻击
  7. 计算机通信基础ppt,计算机网络第2章 数据通信基础知识要点课件.ppt
  8. 影响机器视觉光源效果的因素有哪些?
  9. 深度学习入门:用MNIST完成Autoencoder(续)
  10. 上週末去南投玩了一下,順便拍了几张,拿出来和大家分享