一、问题描述
给出一个数组, 数组中存在一个数据,其出现次数超过一半的的数组长度,求出这个数据;
可以使用快速排序方法, 然后中位数就是要求的数据,其时间复杂度是O(nlogn);
二、基于partition的算法
1) 在数组中随机寻找一个数据pivot,然后调整数组使得pivot 左边的数据都小于pivot, pivot右边的数据都大于pivot, 返回数据pivot的下标索引index;
如果index == mid,即找到了问题的解;
如果index > mid, 在左边集合中继续寻找index;
如果index < mid, 在右边集合中继续寻找index;
具体的代码实现如下:
#include <stdio.h>
#include <stdlib.h>
int partition(int* arr, int i, int j) {
int tmp = arr[i];
while (i < j) {
while (i < j && arr[j] >= tmp)
j--;
arr[i] = arr[j];
while (i < j && arr[i] <= tmp)
i++;
arr[j] = arr[i];
}
arr[i] = tmp;
return i;
}
int MoreThanHalfNum(int* arr, int low, int high) {
if (low >= high)
return -1;
int index = partition(arr, low, high);
int mid = (low + high + 1) / 2;
while (index != mid) {
if (index > mid)
index = partition(arr, low, index - 1);
else
index = partition(arr, index + 1, high);
}
int result = arr[mid];
return result;
}
int main()
{
int arr[] = { 3, 2, 4, 1, 0, 0, 0, 0, 0 };
int len = sizeof(arr) / sizeof(arr[0]);
int ret = MoreThanHalfNum(arr, 0, len - 1);
printf("%d \n", ret);
for (int i = 0; i < len; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
三、基于数组特性的算法改进
在遍历数组的时候保存两个值, 当前数据value 和 当前数据出现的次数time,当遍历下一个数组的时候:
如果下一个数据等于当前数据, time++;
如果下一个数据不等于当前数据, time–;
当time == 0, 说明之前遍历过的数据都已经内部抵消了,更新value为下一个数据;
具体的代码实现如下:
#include <stdio.h>
#include <stdlib.h>
int MoreThanHalfNum(int* arr, int len) {
if (len < 3)
return -1;
int cur;
int times = 0;
for (int i = 0; i < len; i++) {
if (times == 0) {
cur = arr[i];
times++;
}
else if (cur == arr[i])
times++;
else
times--;
}
return cur;
}
int main()
{
int arr[] = { 3, 2, 4, 1, 9, 9, 9, 9, 9 };
int len = sizeof(arr) / sizeof(arr[0]);
int ret = MoreThanHalfNum(arr, len);
printf("%d \n", ret);
return 0;
}