剑指Offer_面试题29_数组中出现次数超过一半的数字
2017-08-15 16:03
489 查看
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。分析:思路一,如果是排序的数组那就好了。快排一次可以确定一个位置的数字,在他的左侧都比他小,右侧都比他大。一个数组中数字超过数组长度一半,经过排序之后,中间的位置一定是这个数字,这个数字也就是统计学上的中位数。
解法一:当且仅当可以修改数组内容时,利用快排分区,排好数组中间位置的数字即为结果,记得要检验是否无效输入;
#include <stdlib.h> #include <stdio.h> //快排一次分区 int partition(int *a, int low, int high) { int value = a[low]; //基准元素 while (low < high) { while (low < high && value <= a[high]) --high; if (low < high) a[low++] = a[high]; while (low < high && a[low] <= value) ++low; if (low < high) a[high--] = a[low]; } a[low] = value; return low; } bool inputInvalid = false; //检查是否真的超过一半 bool CheckInvalidArray(int *numbers, int length, int num) { inputInvalid = false; int times = 0; for (int i = 0; i < length; ++i) { if (numbers[i] == num) ++times; } bool res = true; if (times * 2 <= length) { inputInvalid = true; res = false; } return res; } //解法一:快排求第k大的数值,需要改变数组 int MoreThanHalfNum(int *number, int length) { if (number == NULL || length <= 0) { inputInvalid = true; return 0; } int middle = length >> 1; int start = 0; int index = partition(number, 0, length-1); while (index != middle) { if (index < middle) { index = partition(number, index+1, length-1); } else { index = partition(number, 0, index - 1); } } int result = number[middle]; //这里补充一个检查是不是超过一半的判断 if (!CheckInvalidArray(number, length, result)) result = 0; return result; }
解法二:不改变数组本身,利用数组特性。两个变量,一个result保存数字,一个count保存次数。result初始化为第一个元素,count初始化为1;从第二个元素开始遍历数组,如果count==0则result=当前数字,count = 1;否则如果result=当前数字,count++;否则--count;这样result必定是超过一半的元素,当然最后还是要检验是否有效输入;
//解法二:根据数组特点,不改变数组本身 int MoreThanHalfNum2(int *numbers, int length) { if (numbers == NULL || length <= 0) { inputInvalid = true; return 0; } int result = numbers[0]; int count = 1; for (int i = 1; i < length; ++i) { if (count == 0) { result = numbers[i]; count = 1; } else if (numbers[i] == result) ++count; else --count; } if (!CheckInvalidArray(numbers, length, result)) result = 0; return result; } int main() { int a[] = {1,2,3,2,2,2,5,4,2}; int res = MoreThanHalfNum(a, 9); printf("%d\n", res); int b[] = { 1,2,3,2,2,2,5,4,2 }; int res2 = MoreThanHalfNum2(b, 9); printf("%d\n", res2); getchar(); return 0; }
测试结果:
总结:快排一次分区可以在O(n)时间找到数组中任意第K大的数字,利用好这一点可以解决很多问题,但是会修改数组本身内容,这一点面试的时候一定要问清楚。两种解法时间复杂度都是O(n)。
相关文章推荐
- 剑指offer-----面试题29(数组中出现次数超过一半的数字)
- 剑指offer-面试题29-数组中出现次数超过一半的数字
- (剑指Offer)面试题29:数组中出现次数超过一半的数字
- 剑指offer——面试题29:数组中出现次数超过一半的数字
- 《剑指Offer》学习笔记--面试题29:数组中出现次数超过一半的数字
- 剑指Offer面试题29:数组中出现次数超过一半的数字 Java实现
- 剑指Offer面试题29(java版):数组中出现次数超过一半的数字
- 剑指offer-面试题29-数组中出现次数超过一半的数字
- 剑指offer——面试题29:数组中出现次数超过一半的数字
- 剑指Offer面试题29(java版):数组中出现次数超过一半的数字
- 《剑指offer》面试题29:数组中出现次数超过一半的数字
- 剑指offer面试题29-数组中出现次数超过一半的数字
- 面试题29:数组中出现次数超过一半的数字
- 面试题29—数组中出现次数超过一半的数字
- 【剑指offer】5.2时间效率——面试题29:数组中出现次数超过一半的数字
- 面试题29_数组中出现次数超过一半的数字
- 剑指offer之面试题29:数组中出现次数超过一半的数字
- [剑指offer][面试题29]数组中出现次数超过一半的数字
- 【剑指offer】面试题29:数组中出现次数超过一半的数字
- 面试题29:数组中出现次数超过一半的数字