[LeetCode]第k大数

最近自己在电话面试中,经常被问到,“找出数组中的第k个最大的数”或者“或者找出数组中的前k个最大的数”,都是找出特定的数。首先,可以简单的用快排然后,第k位就是的,但是这样时间复杂度会很高。

一、快速选择算法

这个名字是y总起的,原理很简单。快排是找一个标志位,小于它的放左边,大于它的放右边,这样是不是确定了标志位是多少大的数。比如[2, 4, 3, 5, 1],第一轮取3做标志位,排序后变成[2, 1, 3, 5, 4],这是不是确定了3这个元素,在数组中是第3大数。这样的话,对快排进行改进,从而不需要排序整个数组。

原始快排

public void quickSort(int[] nums, int l, int r) {
		int i = l - 1, j = r + 1, x = nums[(l + r) >> 1];
  	while (i < j) {
      	do {
          i ++;
        } while (nums[i] < x);
      
      	do {
          j --;
        } while (nums[j] > x);
      
      	if (i < j) {
          int temp = nums[i];
          nums[i] = nums[j];
          nums[j] = temp;
        }
    }
  	quickSort(nums, l, j), quickSort(nums, j + 1, r);
}

快速选择算法

//引入了一个k,这个k值得是排序后的数组(从小到大),第k位
//题目中的第k大,要经过转换,quickSort(nums, 0, nums.length, nums.length - k  + 1)
public int quickSort(int[] nums, int l, int r, int k) {
		if(l >= r) {
      return nums[l];
    }
  	
  	int i = l - 1, j = r + 1, x = nums[(l + r) >> 1];
  	while (i < j) {
      	do {
          i ++;
        } while (nums[i] < x);
      
      	do {
          j --;
        } while (nums[j] > x);
      
      	if (i < j) {
          int temp = nums[i];
          nums[i] = nums[j];
          nums[j] = temp;
        }
    }
  	
 		int leftSize = j - l + 1;
  	if (k <= leftSize) {
      	return quickSort(nums, l, j, k);
    } else {
      	return quickSort(nums, j + 1, r, k - leftSize)
    }
}

二、堆排序

我们数据结构中使用的堆,构造一个小顶堆,具有一定的容积限制为k。当容积到大k时,则将新的数和堆顶做比较,决定是否替换。思路比较简单,代码也很简单。

public int getAns(int nums, int k) {
  	PriorityQueue<Integer> heap = new PriorityQueue();
  	for (int num : nums) {
      	if (heap.size() == k) {
          	if (heap.peek() < num) {
              	heap.poll();
              	heap.offer(num);
            }
        } else {
          	heap.offer(num);
        }
    }
  	return heap.peek();
}
posted @ 2021-03-14 15:38  herrhu  阅读(349)  评论(0)    收藏  举报