题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例子
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
链接:
剑指Offer(第2版):P205
LeetCode-169:Majority Element (数组中的多数元素)
- http://blog.csdn.net/koala_tree/article/details/78289902
思路标签:
- 算法:递归
解答:
1. 基于Partition函数的算法(时间复杂度:O(n))
- 数组中出现次数超过一半,所以数组中间的数字一定就是那个出现次数超过数组一半的数字。
- 基于快排算法中的Partition函数,使得比选中的数字小的数字都在它左边,比选中的数字大的数字都在它的右边。
- 如果选中的数字的下标刚好是n/2,那么这个数字就是数组中的中位数;
- 如果它的下标大于n/2,那么中位数应该位于它的左边,继续在左边寻找;
- 如果它的下标小于n/2,那么中位数应该位于它的右边,继续在右边寻找。
- 利用递归实现。
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
bool g_bInputInvalid = false;
bool CheckInvalidArray(int* numbers, int length)
{
g_bInputInvalid = false;
if (numbers == nullptr && length <= 0)
g_bInputInvalid = true;
return g_bInputInvalid;
}
bool CheckMoreThanHalf(int* numbers, int length, int number)
{
int times = 0;
for (int i = 0; i < length; ++i)
{
if (numbers[i] == number)
times++;
}
bool isMoreThanHalf = true;
if (times * 2 <= length)
{
g_bInputInvalid = true;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
void swap(int* data, int i, int j) {
if (i == j) return;
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
// 分区操作
int Partition(int data[], int length, int start, int end) {
if (data == nullptr || length <= 0 || start < 0 || end >= length)
throw new std::exception("Invalid Parameter");
int index = rand() % (end - start + 1) + start; // 随机选择基准
swap(data, index, end);
int small = start - 1;
for (index = start; index < end; ++index) {
if (data[index] < data[end]) {
++small;
if (small != index)
swap(data, small, index);
}
}
++small;
swap(data, small, end);
return small;
}
// ====================方法1====================
int MoreThanHalfNum_Solution1(int* numbers, int length)
{
if (CheckInvalidArray(numbers, length))
return 0;
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(numbers, length, start, end);
while (index != middle)
{
if (index > middle)
{
end = index - 1;
index = Partition(numbers, length, start, end);
}
else
{
start = index + 1;
index = Partition(numbers, length, start, end);
}
}
int result = numbers[middle];
if (!CheckMoreThanHalf(numbers, length, result))
result = 0;
return result;
}
2. 根据数组特点
- 数组中出现次数超过一半,所以该数字出现的次数超过数组长度的一半,也就是它出现的次数比其他所有数字出现次数的和还要多;
- 遍历数组的时候保存两个值:一个是数字,一个是次数。
- 如果下一个数字和保存的数字相同,则次数加1;不相同则减1;如果次数为0,则保存下一个数字,次数设置为1。
- 因为数字超过一半,所以最后一次数字大于1对应的数字则为符合题目要求的数字。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int length = numbers.size();
if(length == 0)
return 0;
int result = numbers[0];
int times = 1;
for(int i=1; i<length; ++i){
if(times == 0){
result = numbers[i];
times = 1;
}
else if(numbers[i] == result)
times++;
else
times--;
}
if(!CheckMoreThanHalf(numbers, result))
return 0;
return result;
}
bool CheckMoreThanHalf(vector<int> &numbers, int number){
int times = 0;
int length = numbers.size();
for(int i=0; i<length; ++i){
if(numbers[i] == number)
times++;
}
bool isMoreThanHalf = true;
if(times * 2 <= length)
isMoreThanHalf = false;
return isMoreThanHalf;
}
};