随机抽取数组中一个元素进行切分并返回该元素下标 index:
index == k-1 切分元素正好为第k个元素index < k-1 第k大的元素在下标为index元素的右边,对index右边的元素进行切分index > k-1 第k大的元素在下标为index元素的左边,对index左边的元素进行切分 class Solution { Random rand = new Random(); public int[] getLeastNumbers(int[] arr, int k) { if(arr == null || arr.length == 0 || arr.length < k || k <= 0) return new int[]{}; int lo = 0; int hi = arr.length - 1; int index = partition(arr, lo, hi); while(index != k - 1){ if(index > k - 1){ hi = index - 1; index = partition(arr, lo, hi); }else if(index < k - 1){ lo = index + 1; index = partition(arr, lo, hi); } } return Arrays.copyOfRange(arr, 0, k); } /** * 随机切分函数 */ private int partition(int[] a, int lo, int hi){ if(a == null || a.length == 0 || lo < 0 || hi > a.length) throw new RuntimeException("Invalid Parameters"); int index = randRange(rand, lo, hi+1); System.out.println(index); exch(a, hi, index); int small = lo - 1; for(index = lo; index < hi; ++index){ if(a[index] < a[hi] ){ ++small; if(index != small){ exch(a, small, index); } } } small++; exch(a, small, hi); return small; } private int randRange(Random rand, int min, int max) { if(max - min == 0) return min; int r = rand.nextInt(max - min) + min; return r; } private void exch(int[] nums, int i, int j){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }使用一个容器添加k个数字。容器含有k个数字之后将新的数字与容器中的最大数字比较,如果新数大于最大值则新数不可能为最小的k个数之一,如果新数小于最大值则将容器的最大值提出,加入新数。 从容器中快速查询最大数可以使用最大优先队列,查询时间复杂度为O(1),基于堆实现的的最大优先队列可以在O(logk)实现删除与插入操作。
class Solution { public int[] getLeastNumbers(int[] arr, int k) { if(arr == null || arr.length == 0 || arr.length < k || k <= 0) return new int[]{}; PriorityQueue<Integer> maxPQ = new PriorityQueue<>(new Comparator<Integer>(){ public int compare(Integer o1, Integer o2) { return o2-o1; } }); for(Integer each : arr){ if(maxPQ.size() < k){ maxPQ.add(each); }else if(each < maxPQ.peek()){ maxPQ.poll(); maxPQ.offer(each); } } int[] ans = new int[k]; for(int i = 0; i < k; i++){ ans[i] = maxPQ.poll(); } return ans; } }采用PriorityQueue实现大小顶堆 解决topK问题