• Solution 5: Top K


    问题描述

    输入一个整形数组和K,输出数组中前K大的元素们。

    解决思路

    思路1:排序

    如果用快排,平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2);空间复杂度为O(logn)~O(n);

    如果用堆排,时间复杂度为O(nlogn),空间复杂度为O(1).

    注意:

    Java中Arrays.sort()方法默认实现为归并排序,时间O(nlogn),空间O(n)。

    思路2:借用快排的partition函数

    较思路1的改进在于,不一定要完全将整个数组进行排序,快排中的partition函数能够保证partition后的元素位置之前的元素均大于等于(或小于等于)该指向元素。

    平均时间复杂度为O(n),最坏时间复杂度和快排的一样O(n^2)。

    思路3:大数据下的堆排

    如果场景为数据量很大,或者甚至是无穷量的数据时,此时可借用堆排的思想。

    具体做法为,如果是输出前K大,那么需要维护一个大小为K的最小堆,之后的元素与堆顶元素进行比较,如果更大则进入堆中,再调整堆。

    时间复杂度为O(n*logk + k),空间复杂度为O(k)。

    程序

    public class TopK {
    	// sort
    	public List<Integer> getTopKBySort(int[] nums, int k) {
    		List<Integer> res = new ArrayList<Integer>();
    		if (nums == null || nums.length == 0 || nums.length < k || k <= 0) {
    			return res;
    		}
    
    		Arrays.sort(nums);
    		for (int i = 0; i < k; i++) {
    			res.add(nums[i]);
    		}
    		return res;
    	}
    	
    	// partition
    	public List<Integer> getTopKByPartition(int[] nums, int k) {
    		List<Integer> res = new ArrayList<Integer>();
    		if (nums == null || nums.length == 0 || nums.length < k || k <= 0) {
    			return res;
    		}
    
    		int part = partition(nums, 0, nums.length - 1);
    		while (true) {
    			if (part == k - 1) {
    				for (int i = 0; i < k; i++) {
    					res.add(nums[i]);
    				}
    				break;
    			} else if (part < k - 1) {
    				part = partition(nums, part + 1, nums.length - 1);
    			} else {
    				part = partition(nums, 0, part - 1);
    			}
    		}
    		
    		return res;
    	}
    
    	private int partition(int[] nums, int begin, int end) {
    		int low = begin - 1, high = end;
    		int pivot = nums[end];
    
    		while (true) {
    			while (low < high && nums[++low] >= pivot) {
    				;
    			}
    			while (low < high && nums[--high] <= pivot) {
    				;
    			}
    			if (low >= high) {
    				break;
    			}
    			swap(nums, low, high);
    		}
    		swap(nums, low, end);
    		return low;
    	}
    
    	private void swap(int[] nums, int low, int high) {
    		int tmp = nums[low];
    		nums[low] = nums[high];
    		nums[high] = tmp;
    	}
    	
    	// heap
    	public int[] getTopKByHeap(int[] nums, int k) {
    		if (nums == null || nums.length == 0 || nums.length < k || k <= 0) {
    			return null;
    		}
    		
    		int[] res = new int[k];
    		for (int i = 0; i < nums.length; i++) {
    			if (i < k) {
    				res[i] = nums[i];
    			} else if (i == k) {
    				buildMinHeap(res);
    			} else {
    				if (nums[i] > res[0]) {
    					res[0] = nums[i];
    					fixMaxDown(res, 0);
    				}
    			}
    		}
    		
    		return res;
    	}
    
    	private void fixMaxDown(int[] heap, int i) {
    		int tmp = heap[i];
    		int j = 2*i +1;
    		
    		while (j < heap.length) {
    			while (j+1 < heap.length && heap[j+1] < heap[j]) {
    				++j;
    			}
    			if (tmp<heap[j]) {
    				break;
    			}
    			heap[i] = heap[j];
    			i = j;
    			j = 2*i + 1;
    		}
    		
    		heap[i] = tmp;
    	}
    
    	private void buildMinHeap(int[] heap) {
    		for (int i = heap.length/2 - 1; i >= 0; i--) {
    			fixMaxDown(heap, i);
    		}
    	}
    }
    
  • 相关阅读:
    Redis网络连接库剖析
    如何下载和安装pywin32
    Python游戏开发入门:pygame事件处理机制
    python常见错误
    波特率与比特率
    __gcd最大公约数
    动态规划算法之矩阵连乘问题
    二分插入排序+二分搜索
    office 总结
    javaWeb总结
  • 原文地址:https://www.cnblogs.com/harrygogo/p/4607159.html
Copyright © 2020-2023  润新知