在不增加空间复杂度的情况下,用堆排序。维护一个大小为k的堆。如果是找最大的K个值,那么用大顶堆,否则用小顶堆。
先从原数组中取k个值建立一个堆,然后每次从原数组中拿一个值与堆顶元素进行比较,看是否需要替换,如果替换了,就进行一次堆排序。这样到最后,这个堆中的元素就是top K。
前K大,维护最小堆;前K小,维护最大堆
1.初始化一个最小堆
2.输入新数据,若大于堆顶则替换堆顶,调整堆为最小堆(从最后一个父节点开始调整)
3.遍历完数据,遍历完数据,堆中数据即为所求
复杂度O(n*logK)
可以参考下面的代码。
class Solution {
public int findKthLargest(int[] nums, int k) {
int[] topK = new int[k];
for(int i=0; i<k; i++){
topK[i] = nums[i];
System.out.println(topK[i]);
}
heapSort(topK);
System.out.println(topK[0]);
for(int j=k; j<nums.length; j++){
if(nums[j]>topK[0]){
topK[0] = nums[j];
sort(topK, 0, k);
}
}
return topK[0];
}
public void sort(int[] nums, int index, int size){
int i = index;
int j = 2*index+1;
while(j<size-1){
if(j<size-1 && nums[j]>nums[j+1])
j++;
if(nums[i]<nums[j])
break;
else{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i = j;
j = 2*i+1;
}
}
}
public void heapSort(int[] nums){
for(int i=nums.length/2; i>=0; i--){
sort(nums, i, nums.length);
}
// for(int i=1; i<nums.length; i++){
// int temp = nums[i];
// nums[i] = nums[nums.length-i+1];
// nums[nums.length-i+1] = temp;
// sort(nums, 1, nums.length-i);
// }
}
}
还有递归版的:
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> res=new ArrayList<>();
// 先用hashmap统计词频
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i])) {
map.put(nums[i],map.get(nums[i])+1);
}
else {
map.put(nums[i],1);
}
}
int[] nums2=new int[map.size()];
int index=0;
for(Integer key:map.keySet()){
nums2[index++]=map.get(key);
}
// 对map中的词频提取前K
// 方法二:堆排序
int []top=topK(nums2,k);
// 找到词频对应的数(方法二)
for(int i=0;i<k;i++){
// map.keySet():返回set类型 map.values():collection类型
for(Integer key:map.keySet()){
if(map.get(key)==top[i]) {
if(res.size()==k) return res;
res.add(key);
// 去重 map更新值:put方法覆盖原先数据
map.put(key,0);
}
}
}
return res;
}
// 方法二:堆排序
// 调整堆 递归过程
public void adjust(int nums[],int size,int index){
// 调整规则:比较父节点和子节点(left,right)
int left=2*index+1;
int right=2*index+2;
// index为调整前父节点
int min=index;
if(left<size && nums[left]<nums[min]) min=left;
if(right<size && nums[right]<nums[min]) min=right;
// 交换位置
if(min!=index){
int temp=nums[min];
nums[min]=nums[index];
nums[index]=temp;
//递归调整堆
adjust(nums,size,min);
}
}
// 建堆
public void buildHeap(int[] nums){
int length=nums.length;
// 从length/2-1开始调整
for(int i=length/2-1;i>=0;i--){
adjust(nums,length,i);
}
}
// 查找topK
public int[] topK(int[] nums,int k){
int top[]=new int[k];
for(int i=0;i<k;i++) top[i]=nums[i];
// 初始化堆
buildHeap(top);
// 输入数据,更新堆
for(int j=k;j<nums.length;j++){
if(nums[j]>top[0]){
top[0]=nums[j];
adjust(top,k,0);
}
}
return top;
}
}