剑指Offer_面试题29_数组中出现次数超过一半的数字

来源:互联网 发布:钓鱼软件什么意思 编辑:程序博客网 时间:2024/06/08 16:59

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为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)。
阅读全文
0 0
原创粉丝点击