问题描述
Given a non-empty array of integers, return the k most frequent elements.
非空的整型数组,返回K个出现次数最频繁的元素
举例说明
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]Example 2:
Input: nums = [1], k = 1 Output: [1]
注意
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
- It's guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
- You can return the answer in any order.
- 可以假设k是合理的,k的范围在[1,number]
- 算法的时间复杂度必须小于O(nlogn),n为数组长度(非翻译:然而实践证明,O(nlogn)也是可以通过的)
- 保证答案是唯一的,话句话说前k个频次最高的元素是唯一的。
- 可以以任意顺序返回
实现
快速排序O(nlogn)
我原本是想使用堆实现的,然而在C语言中判断收集频次这里无论如何都需要O(n²)来实现。写到哭泣……
后来学了快速排序,发现正好可以应用上。
快速排序的平均时间复杂度和最佳时间复杂度为O(nlogn),最坏时间复杂度为O(n²)。随机选取pivot index可以避免最坏时间复杂度。
我们还需要声明新的结构体Freq用来记录数组元素和出现次数。
首先对数组进行快速排序(O(nlogn)),方便用Freq类型的数组freq记录每个元素和出现次数(O(n))。
然后对freq进行快速排序,返回前k个Freq对象的element属性即可。
这个代码十分冗余的地方是对整型数组和Freq类型的数组分别写了快速排序的函数。因为不会兼容因为他们的类型不同,so代码略长。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct Freq Freq;
struct Freq{
int element;
int times;
};
void swap_element(int *a,int *b){
int tmp = *a;
*a=*b;
*b=tmp;
}
int random_partition(int *arr, int start, int end){
int pIndex1 = rand()%(end-start+1)+start;
swap_element(arr+pIndex1,arr+end);
int pivot = arr[end];
int pIndex2 = start;
for(int i=start;i<end;i++){
if(arr[i]<=pivot){
swap_element(arr+i,arr+pIndex2);
pIndex2++;
}
}
swap_element(arr+pIndex2,arr+end);
return pIndex2;
}
void quick_sort(int *arr, int start, int end){
if(start<end){
int pIndex = random_partition(arr, start,end);
printf("pIndex=%d\n",pIndex);
quick_sort(arr,start,pIndex-1);
quick_sort(arr,pIndex+1,end);
}
}
//------------------------------------------------------------------------------------------------
void freq_swap_element(Freq *a,Freq *b){
int element = a->element;
int times = a->times;
a->element = b->element;
a->times = b->times;
b->element = element;
b->times = times;
}
int freq_random_partition(Freq *arr, int start, int end){
int pIndex1 = rand()%(end-start+1)+start;
freq_swap_element(arr+pIndex1,arr+end);
int pivot = arr[end].times;
int pIndex2 = start;
for(int i=start;i<end;i++){
if(arr[i].times>=pivot){
freq_swap_element(arr+i,arr+pIndex2);
pIndex2++;
}
}
freq_swap_element(arr+pIndex2,arr+end);
return pIndex2;
}
void freq_quick_sort(Freq *arr, int start, int end){
if(start<end){
int pIndex = freq_random_partition(arr, start,end);
freq_quick_sort(arr,start,pIndex-1);
freq_quick_sort(arr,pIndex+1,end);
}
}
int* topKFrequent(int* nums, int numsSize, int k, int* returnSize){
*returnSize=k;
quick_sort(nums,0,numsSize-1);
printf("sort done\n");
Freq *freq = malloc(sizeof(Freq)*numsSize);
freq[0].element=nums[0];
freq[0].times = 1;
int j=0;
for(int i=1;i<numsSize;i++)
{
if(nums[i]==freq[j].element){
freq[j].times++;
}else
{
j++;
freq[j].element=nums[i];
freq[j].times = 1;
}
}
printf("freq filled out\n");
freq_quick_sort(freq,0,j);
printf("freq sort done\n");
int *ret = malloc(sizeof(int)*k);
for(int i=0;i<k;i++){
ret[i]=freq[i].element;
}
return ret;
}