剑指Offer:面试题29 数组中出现次数超过一半的数字
2014-09-08 20:04
561 查看
/* 数组中出现次数超过一半的数字: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组{1,2,3,2,2,2 ,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。 1 基于Partition函数的O(n)解法: 如果将数组排序,那么数组中间的数字时出现次数超过数组长度一半的数字。 用随机选择快速排序算法,在数组中随机选择一个数字,如果选中的数字的下标刚好是n/2,这个数字就是中位数。 如果选中的下标大于n/2,那么中位数在它的左边。 注意:最后还需要对返回的数字,检查其是否次数超过一半 2根据数组特点找出O(n)的算法: 数组中有一个数字出现的次数超过数组长度的一半 = 出现次数>其他所有数字出现次数和 遍历数组时保存两个值:1数组中的数字,2次数 当遍历到下一个数字的时候:如果下一个数字和之前保存的数字相同,则次数累加 不同,次数减1 当次数为0时:我们需要保存下一个数字,并将次数设为1。 要找的数字出现的次数比其他所有数字出现的次数之和都要多,因此要找的数字肯定是最后一次把次数 设为1时对应的数字。?为什么是最后一次设为1 输入: 每个测试案例包括2行: 第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。 第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。 输出: 对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。 样例输入: 9 1 2 3 2 2 2 5 4 2 8 1 2 3 2 2 5 4 2 样例输出: 2 -1 */ /* 关键: 1 基于Partition函数的O(n)解法: 如果将数组排序,那么数组中间的数字时出现次数超过数组长度一半的数字。 用随机选择快速排序算法,在数组中随机选择一个数字,如果选中的数字的下标刚好是n/2,这个数字就是中位数。 如果选中的下标大于n/2,那么中位数在它的左边。 2 swap(&iArr[low],&iArr[iIndex]);//注意:快速排序之随机枢轴版中,注意要将随机枢轴与iArr[low]进行交换 3 int iIndex = partition(low,high); while(iIndex != iMid) { if(iIndex > iMid)//如果下标大于中间,应该向左缩小范围 { high = iIndex - 1; } 4 for(int i = 0 ; i < iLen ; i++)//注意,需要检查是否真正出现的次数超过了一半 { if(iRes == iArr[i]) { iCnt++; } } if(iCnt*2 <= iLen) 5 根据数组特点找出O(n)的算法: 数组中有一个数字出现的次数超过数组长度的一半 = 出现次数>其他所有数字出现次数和 要找的数字出现的次数比其他所有数字出现的次数之和都要多,因此要找的数字肯定是最后一次把次数 设为1时对应的数字。?为什么是最后一次设为1。因为只有最后一次设为1说明相同的数字个数>不同的数字个数 6 if(iTimes == 0)//如果次数减为0,就令结果为当前数,并使次数为1 { iRes = iArr[i]; iTimes = 1; } else if(iRes == iArr[i])//如果当前数与之前保存的数相同,就累加 { iTimes++; } else//如果当前数与之前保存的数不同,就累减 */ #include <stdio.h> #include <string.h> #include <stdlib.h> const int MAXSIZE = 100001; int iArr[MAXSIZE]; //注意:随机选择枢轴的排序版本与原版本不能混淆,会出事 int randomInRange(int min,int max) { return (rand() % (max - min + 1) + min);//注意这里采用:取余来限定范围,通过加上min来获取[min,max]指定范围内的数 } void swap(int* p1,int* p2) { int iTemp = *p1; *p1 = *p2; *p2 = iTemp; } int partition(int low,int high) { int iIndex = randomInRange(low,high); swap(&iArr[low],&iArr[iIndex]);//注意:快速排序之随机枢轴版中,注意要将随机枢轴与iArr[low]进行交换 int iAxis = iArr[low];//轴:axis while(low < high) { while(low < high && iArr[high] >= iAxis) { high--; } iArr[low] = iArr[high]; while(low < high && iArr[low] <= iAxis) { low++; } iArr[high] = iArr[low]; } iArr[low] = iAxis; return low; } int moreThanHalfNum(int iLen) { int iMid = iLen >> 1; int low = 0,high = iLen -1; int iIndex = partition(low,high); while(iIndex != iMid) { if(iIndex > iMid)//如果下标大于中间,应该向左缩小范围 { high = iIndex - 1; } else { low = iIndex + 1; } iIndex = partition(low,high); } int iRes = iArr[iMid]; int iCnt = 0; for(int i = 0 ; i < iLen ; i++)//注意,需要检查是否真正出现的次数超过了一半 { if(iRes == iArr[i]) { iCnt++; } } if(iCnt*2 <= iLen) { return -1; } else { return iRes; } } int moreThanHalfNum2(int iLen) { int iRes = iArr[0]; int iTimes = 1; for(int i = 1 ; i < iLen ;i++) { if(iTimes == 0)//如果次数减为0,就令结果为当前数,并使次数为1 { iRes = iArr[i]; iTimes = 1; } else if(iRes == iArr[i])//如果当前数与之前保存的数相同,就累加 { iTimes++; } else//如果当前数与之前保存的数不同,就累减 { iTimes--; } } int iCnt = 0; for(int i = 0 ; i < iLen ; i++) { if(iRes == iArr[i]) { iCnt++; } } if(iCnt*2 <= iLen) { return -1; } else { return iRes; } } void process() { int n; while(EOF != scanf("%d",&n)) { memset(iArr,0,sizeof(iArr)); for(int i = 0 ; i < n ; i++) { scanf("%d",&iArr[i]); } printf("%d\n",moreThanHalfNum(n)); printf("%d\n",moreThanHalfNum2(n)); } } int main(int argc,char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- [剑指offer][面试题29]数组中出现次数超过一半的数字
- 剑指offer 面试题29 数组中出现次数超过一半的数字
- 剑指offer面试题[29]-数组中出现次数超过一半的数字
- 剑指Offer----面试题29:数组中出现次数超过一半的数字
- 剑指Offer面试题29数组中出现次数超过一半的数字(涉及快排)
- 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)
- 【剑指offer】5.2时间效率——面试题29:数组中出现次数超过一半的数字
- 剑指offer之面试题29:数组中出现次数超过一半的数字
- 剑指offer面试题29-数组中出现次数超过一半的数字
- 剑指offer面试题29:数组中出现次数超过一半的数字
- 【剑指Offer学习】【面试题29 :数组中出现次数超过一半的数字】
- 算法题005 剑指Offer面试题29 数组中出现次数超过一半的数字
- 剑指offer--面试题29:数组中出现次数超过一半的数字
- 剑指offer 面试题29—数组中出现次数超过一半的数字
- 剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)
- 剑指offer之面试题29数组中出现次数超过一半的数字
- 【剑指Offer】面试题29:数组中出现次数超过一半的数字
- 【剑指offer】面试题29:数组中出现次数超过一半的数字
- 剑指offer-面试题29 找到数组中出现次数超过一半的数字-1
- 剑指Offer之面试题29:数组中出现次数超过一半的数字