题目:
数组中有一个数字出现次数超过数组长度的一半,请找出这个数字。
边界条件或异常:
数组为空或只有一个元素,或数组中没有数字超过数组长度的一半。
思路:
方法一:可以先进行排序(O(nlgn))再从头到尾一次寻找超过数组长度一半的数字(O(nlgn))。
注意这种方法的前提是可以改变原数组。
注意排序后中间数字即是
时间复杂度:O(nlgn)
空间复杂度:O(1)
方法二:可以用hash表将出现的数字的次数存下来,重复出现时,次数加1,然后查hash表中超过数组长度一半的数字即可。
注意这种方法不用修改原来的数组
时间复杂度:O(n)
空间复杂度:O(n)
方法三:因为数组中有一个数字出现的次数超过数组长度的一半,也就是它出现的次数比其他所有数字出现的次数和还要多,因此我们可以保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历下一个数字时,如果和之前保存的数字相同,则次数加1;如果不同,则减1;如果次数为0,需要保存下一个数字,并把次数设为1。我们要找的数字是最后一次把次数设为1时对应的数字。
注意最后检验该数字出现的次数是否达到一半。
时间复杂度:O(n)
空间复杂度:O(1)
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;
bool check(vector<int> nums, int result)
{
int times = 0;
for (int i = 0; i < nums.size(); i++)
if (nums[i] == result) times++;
if (times * 2 <= nums.size()) return false;
return true;
}
int moreThanHalfNum(vector<int> nums)
{
int size = nums.size();
if (size == 0) return 0;
int times = 1;
int result = nums[0];
for (int i = 1; i < size; i++)
{
if (times == 0)
{
result = nums[i];
times = 1;
}
else if (nums[i] == result) ++times;
else --times;
}
return check(nums,result)?result:0;
}
int main()
{
int arr[] = { 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 };
vector<int> nums(arr, arr + 12);
cout << moreThanHalfNum(nums) << endl;
return 0;
}