更多剑指offer面试题请点击:《剑指offer》(第二版)题集目录索引
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
解题思路:
数组中一个数字出现的次数超过数组长度的一半,那就是说其他数字出现的次数之和都比它出现的次数还少。所以我们可以遍历一遍数组,并且遍历时保存两个值:一个是数组的某个元素,二是次数。
当遍历的下个数字和遍历之前保存的数字相同,那次数就加1;当遍历的下个数字和遍历之前保存的数字不相同,那次数就减1。如果次数为0,那我们需要保存下一个数字并把次数置为1。
因为我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么我们要找的那个数肯定就是最后一次把次数置为1时对应的那个数。
< code >
int MoreThanHalfNum(int* numbers, int length)
{
if (CheckInvalidArray(numbers, length)) //判断数组是否为空
return 0;
int i = 0;
int result = numbers[0]; //保存数组中的元素
int time = 1; //次数
for (i = 1; i < length; i++)
{
/*次数为0,保存下一个数字并把次数置为1*/
if (0 == time)
{
result = numbers[i];
time = 1;
}
/*遍历的下个数字和遍历之前保存的数字相同,次数就加1*/
else if (result == numbers[i])
time++;
/*遍历的下个数字和遍历之前保存的数字不相同,次数就减1*/
else
time--;
}
/*数组中没有哪个数字出现的次数超过数组长度一半*/
if (!CheckMoreThanHalf(numbers, length, result))
result = 0;
return result;
}
上面我们已经基本完成了题目的要求,但我们不但要写出效率高的代码,还要写出鲁棒性强的代码,所以就要考虑一些特殊情况,比如:传数组的地址时传过来一个NULL或者传过来的这个数组中没有哪个数字出现的频率达到题目的要求。此时我们就要增加一些判断。
< code >
/*标识输入的数组是否出错,为1时表示出错,为0时表示正常*/
int g_bInputInvalid = 0;
int CheckInvalidArray(int* numbers, int length)
{
g_bInputInvalid = 0;
if (NULL == numbers || length <= 0)
g_bInputInvalid = 1;
return g_bInputInvalid;
}
int CheckMoreThanHalf(int* numbers, int length, int number)
{
int time = 0;
int i = 0;
for(i = 0; i < length; i++)
{
if (number == numbers[i])
time++;
}
/*标识找到的数字number出现的频率是否符合要求,符合标识值为1,反之为0*/
int isMoreThanHalf = 1;
if (time * 2 <= length)
{
g_bInputInvalid = 1;
isMoreThanHalf = 0;
}
return isMoreThanHalf;
}
测试代码:
void Test(char* testName, int* numbers, int length, int expectedValue, int expectedFlag)
{
if (testName != NULL)
printf("%s begins: ", testName);
int* copy = (int*)malloc(length*sizeof(int));
for (int i = 0; i < length; ++i)
copy[i] = numbers[i];
int result = MoreThanHalfNum(numbers, length);
if (result == expectedValue && g_bInputInvalid == expectedFlag)
printf("Passed.\n");
else
printf("Failed.\n");
free(copy);
copy = NULL;
}
// 存在出现次数超过数组长度一半的数字
void Test1()
{
int numbers[] = { 1, 2, 3, 2, 2, 2, 5, 4, 2 };
Test("Test1", numbers, sizeof(numbers) / sizeof(int), 2, 0);
}
// 不存在出现次数超过数组长度一半的数字
void Test2()
{
int numbers[] = { 1, 2, 3, 2, 4, 2, 5, 2, 3 };
Test("Test2", numbers, sizeof(numbers) / sizeof(int), 0, 1);
}
// 出现次数超过数组长度一半的数字都出现在数组的前半部分
void Test3()
{
int numbers[] = { 2, 2, 2, 2, 2, 1, 3, 4, 5 };
Test("Test3", numbers, sizeof(numbers) / sizeof(int), 2, 0);
}
// 出现次数超过数组长度一半的数字都出现在数组的后半部分
void Test4()
{
int numbers[] = { 1, 3, 4, 5, 2, 2, 2, 2, 2 };
Test("Test4", numbers, sizeof(numbers) / sizeof(int), 2, 0);
}
// 数组中只有一个元素
void Test5()
{
int numbers[] = { 1 };
Test("Test5", numbers, 1, 1, 0);
}
// 输入空指针
void Test6()
{
Test("Test6", NULL, 0, 0, 1);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
system("pause");
return 0;
}
运行结果: