题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{ 1, 2, 3, 2, 2, 2, 5, 4, 2 }。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
方法一:
分析:第一种方法比较简单,利用关联容器map。
源代码如下:
#include<iostream>
#include<map>
using std::cout;
using std::endl;
using std::map;
void FindElement1(int *arr, int length)
{
if (arr == NULL || length <= 0)
{
cout << "输入的参数不符合条件" << endl;
return;
}
map<int, size_t> myMap;
for (int i = 0; i < length; i++)
myMap[arr[i]]++;
for (const auto &temp : myMap)
{
if (temp.second > static_cast<size_t>(length / 2))
{
cout << temp.first << endl;
return;
}
}
cout << "数组中不存在出现次数次数超过一半的数字" << endl;
}
void test11()
{
cout << "\t=========存在=========" << endl;
int arr[] = { 1, 2, 3, 2, 2, 2, 5, 4, 2 };
FindElement1(arr, sizeof(arr) / sizeof(arr[0]));
}
void test12()
{
cout << "\t=========bu存在=========" << endl;
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
FindElement1(arr, sizeof(arr) / sizeof(arr[0]));
}
int main()
{
test11();
test12();
system("pause");
return 0;
}
=========存在=========
2
=========bu存在=========
数组中不存在出现次数次数超过一半的数字
请按任意键继续. . .
方法二:
分析:数组中有一个数字超过了数组长度的一半,将该数组排序,那么中间的数字不就是想要输出的数字吗?稍微麻烦的一点就是,怎么确定排序之后的中间数字出现的次数到底是不是超过了数组长度的一半了呢?
源代码如下(快速排序,算法时间复杂度O(nlogn)):
#include<iostream>
using std::cout;
using std::endl;
void show(int *arr, int length);
void QuickSort(int *arr, int left, int right);
void Judge(int *arr, int length);
void show(int *arr, int length)
{
for (int i = 0; i < length; i++)
cout << arr[i] << " ";
cout << endl;
}
void QuickSort(int *arr, int left, int right)
{
if (left < right)
{
int X = arr[left];
int i = left;
int j = right;
while (i < j)
{
while (arr[j] >= X && i < j)
--j;
if (i < j)
arr[i++] = arr[j];
while (arr[i] <= X && i < j)
++i;
if (i < j)
arr[j--] = arr[i];
}
arr[i] = X;
QuickSort(arr, left, i - 1);
QuickSort(arr, i + 1, right);
}
}
void Judge(int *arr, int length)
{
if (arr == NULL || length <= 0)
{
cout << "输入的数组不符合条件" << endl;
return;
}
QuickSort(arr, 0, length - 1);
int num = arr[length / 2];
int count = 1;
for (int i = 0; i < length ; i++)
{
if (num == arr[i])
++count;
}
if (count > length / 2)
cout << num << endl;
else
cout << "不存在" << endl;
}
void test21()
{
cout << "\t=========存在=========" << endl;
int arr[] = { 1, 2, 3, 2, 2, 2, 5, 4, 2 };
int length = sizeof(arr) / sizeof(arr[0]);
Judge(arr, length - 1);
}
void test22()
{
cout << "\t=========bu存在=========" << endl;
int arr[] = { 1, 2, 3, 2, 5, 6, 5, 4, 2 };
int length = sizeof(arr) / sizeof(arr[0]);
Judge(arr, length - 1);
}
int main()
{
test21();
test22();
system("pause");
return 0;
}
运行结果:
=========存在=========
2
=========bu存在=========
不存在
请按任意键继续. . .
方法三:
分析:数组中的一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现的次数的和还有多。因此我们考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和前一个数字相同,则次数加1,否则次数减1,如果次数为零,我们需要保存下一个数字,并将次数设置为1.由于我们要找的数字出现的次数比其他所有数字出现的次数总和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。
源代码如下:
#include<iostream>
using std::cout;
using std::endl;
bool InputInvalid = false;
//判断输入的数组是否有效
bool checkInvalidArray(int *arr, int length)
{
InputInvalid = false;
if (arr == NULL || length <= 0)
InputInvalid = true;
return InputInvalid;
}
//判断得到的数字是否超过了数组总数的一半
bool checkMoreThanHalf(int *arr, int length, int number)
{
int times = 0;
for (int i = 0; i < length; ++i)
{
if (arr[i] == number)
++times;
}
bool isMoreThanHalf = true;
if (times * 2 <= length)
{
InputInvalid = true;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
int MoreThanHalfNum(int *arr, int length)
{
if (checkInvalidArray(arr, length))
return 0;
int result = arr[0];
int times = 1;
for (int i = 1; i < length; ++i)
{
if (times == 0)
{
result = arr[i];
times = 1;
}
else if (arr[i] == result)
{
++times;
}
else
--times;
}
if (!checkMoreThanHalf(arr, length, result))
return 0;
return result;
}