数组中出现次数超过一半的数字_Glodon(7)_20160923
来源:互联网 发布:什么是网络市场营销 编辑:程序博客网 时间:2024/05/17 02:32
题目描述
数组中有一个数字的出现次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,3,2,3,3,3,2,3,5},数字3出现5次,超过了数组长度的一半,因此输出3.
题目分析
首先想到的方法是先对数组排序,那么排序后数组的中间位置的数一定是出现次数超过一半的数字。也就是求中位数,即长度为n的数组中第n/2大的数字。《剑指offer》中有说有成熟的O(n)的算法得到数组中任意第k大的数字。该方法是基于随机快速排序算法的思想,现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中位置上的数字小的数字排在它的左边,比选中的位置上的数字大的排到它的右边。果果这个选中的数字的下标刚好是n/2,那么这个数字就是数组的中位数。如果它的下标大于n/2,那么中位数在它的左边,只需要接着在它的左边部分的数组查找。同理反之则向右边查找。注意这里和快排不同的是快排需要将枢轴左右两边都进行排序,而本题只需要排一边即可。我们知道随机快排的时间复杂度是O(nlogn),而本题计算复杂度过程较复杂这里略过,但是其最终时间复杂度是O(n)。以上源代码见下面“解法2”。
另一种解法比较巧妙,是根据数组的特点解决此问题,数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现次数的和还要多。因此,我们可以在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字时,如果下一个数字和我们之前保存的数字相同,则次数加1;如果不同 ,则次数减1。如果次数为0,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字次数比其他所有数字出现次数的和还要多,那么最后一次把次数设为1所对应的数字就是我们要找的数字。该算法时间复杂度也是O(n)。源代码见“解法1”。
源代码如下
/******************解法1:基于数组特点******************/bool InputInvalid = false;//全局变量,表征输入是否有效的变量。int morethanHalfNum(int* array, int length){ if(array == 0 || length < 0) { InputInvalid = true; return 0; } int result = array[0]; int times = 1; for(int i = 1; i < length; ++i) { if(times == 0) { result = array[i]; times =1; } else if(array[i] == result) times++; else times --; } //检查result是否符合要求,即出现次数是否超过数组长度的一半 if(!checkMoreThanHalf(array, length, result)) result = 0; return result;}//检查result是否符合要求,即出现次数是否超过数组长度的一半bool checkMoreThanHalf(int* array, int length, int result){ int times = 0; for(int i = 0; i < length; ++i) if(array[i] == result) times++; if(times * 2 <= length) { InputInvalid = true; return false; } else return true;}/******************解法2:基于Partition******************/int morethanHalfNum2(int* array, int length){ if(array == 0 || length < 0) { InputInvalid = true; return 0; } int middle = length >> 1; int start = 0; int end = length -1; //将数组中数字分为两部分,比选择的数字小的数字移到数组的左边,大的移到数组的右边,返回选择的数字的索引(数组下标) int index = Partition(array, length, start, end); while(index != middle) { if(index > middle) Partition(array, length, start, index - 1); else Partition(array, length, index + 1, end); } int result = array[middle]; if(!checkMoreThanHalf(array, length, result)) result = 0; return result;}//将数组中数字分为两部分,比选择的数字小的数字移到数组的左边,大的移到数组的右边,返回选择的数字的索引(数组下标)int Partition(int* array, int length, int start, int end){ if(array == NULL || length <= 0 || start < 0 || end >= length) throw new std::exception("INvalid Parameters"); //在strat 和 end 之间生成一个随机数; int index = RandomInRange(start, end); //交换两个数字 Swap(&array[index], &array[end]); int small = start - 1; for(int i = start; i < end; ++i) { if(array[i] < array[end]) { small++; if(small != i) Swap(&array[small], &array[i]); } } ++small; Swap(&array[small], &array[end]); return small;}int RandomInRange(int min, int max){ int random = rand() % (max - min + 1) + min; return random;}//交换两个数字void Swap(int* num1, int* num2){ int temp = *num1; *num1 = *num2; *num2 = temp;}//既然写到这里,再写个基于Partition的随机快排好了void QuickSort(int* array, int length, int start, int end){ if(array == NULL || length < 0 || start >= end ) return; int index = Partition(array, length, start, end); if(index > start) QuickSort(array, length, start, index - 1); if(index < end) QuickSort(array, length, index + 1, end);}
- 数组中出现次数超过一半的数字_Glodon(7)_20160923
- 数组中超过出现次数超过一半的数字
- 74.数组中超过出现次数超过一半的数字
- 74 数组中超过出现次数超过一半的数字
- 【数组4】数组中出现次数超过一半的数字
- 数组4:数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字
- 找出数组中出现次数超过长度一半的数字
- 2-数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字[算法]
- 数组中出现次数超过一半的数字
- 找出数组中出现次数超过一半的数字--百度
- 数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字
- 寻找数组中出现次数超过一半的数字
- 面试训练数组中出现次数超过一半的数字
- HTML+CSS基础 内联样式表与嵌入样式表设置不同时,听内联的
- 访问服务器中tomcat,重启及关闭tomcat服务器
- java之枚举类 Enum学习笔记
- <Unity3D>Unity3D中LineRenderer的使用
- Android开发之AlertDialog
- 数组中出现次数超过一半的数字_Glodon(7)_20160923
- VS2015使用小技巧 如何使用VS2015创建写HTML代码的项目
- 升级iOS10后app不能删除也不能下载
- php增加模块的方法
- Mono简介
- src/ndarray/ndarray.cc:347: GPU is not enabled
- web安全的威胁:sql注入、xss攻击
- #define 宏的另一种使用
- 磁盘调度算法寻道问题