返回

谈谈数组中的第K个最大元素!

见解分享

谈谈数组中的第K个最大元素!

寻找数组中的第K个最大元素是一个经典的算法问题,经常出现在编程面试和实际项目中。为了解决这个问题,我们可以使用以下步骤:

  1. 维护一个含有K个元素的小顶堆。 小顶堆是一种数据结构,其中每个节点的值都小于或等于其子节点的值。我们可以使用小顶堆来跟踪数组中最大的K个元素。
  2. 以数组的前K个元素建一个小顶堆。 我们可以使用堆排序算法或其他方法来实现这一点。
  3. 扫一遍数组的剩下N-K个元素,当遇到大于堆顶的元素,删掉堆顶,把这个元素加入堆并build。 这样,小顶堆中始终包含数组中最大的K个元素。
  4. 扫完后,堆顶即为结果。

以下是一些具体的实现细节:

  • 我们可以使用数组来实现小顶堆。数组的第一个元素是堆顶,最后一个元素是堆底。
  • 我们可以使用以下函数来插入一个元素到小顶堆中:
void insert(int[] heap, int element) {
  // 将元素添加到堆的末尾
  heap[heap.length - 1] = element;
  // 将元素上浮到正确的位置
  int i = heap.length - 1;
  while (i > 0 && heap[i] < heap[(i - 1) / 2]) {
    // 交换元素的位置
    int temp = heap[i];
    heap[i] = heap[(i - 1) / 2];
    heap[(i - 1) / 2] = temp;
    // 更新索引
    i = (i - 1) / 2;
  }
}
  • 我们可以使用以下函数来删除堆顶元素:
int remove(int[] heap) {
  // 将堆顶元素与堆底元素交换
  int temp = heap[0];
  heap[0] = heap[heap.length - 1];
  heap[heap.length - 1] = temp;
  // 将堆底元素删除
  int element = heap[heap.length - 1];
  heap.length--;
  // 将堆顶元素下沉到正确的位置
  int i = 0;
  while (i < heap.length / 2) {
    int leftChildIndex = 2 * i + 1;
    int rightChildIndex = 2 * i + 2;
    int smallerChildIndex;
    if (leftChildIndex < heap.length && heap[leftChildIndex] < heap[i]) {
      smallerChildIndex = leftChildIndex;
    } else {
      smallerChildIndex = i;
    }
    if (rightChildIndex < heap.length && heap[rightChildIndex] < heap[smallerChildIndex]) {
      smallerChildIndex = rightChildIndex;
    }
    if (smallerChildIndex != i) {
      // 交换元素的位置
      temp = heap[i];
      heap[i] = heap[smallerChildIndex];
      heap[smallerChildIndex] = temp;
      // 更新索引
      i = smallerChildIndex;
    } else {
      break;
    }
  }
  return element;
}
  • 我们可以使用以下函数来找到数组中的第K个最大元素:
int findKthLargest(int[] nums, int k) {
  // 创建一个小顶堆
  int[] heap = new int[k];
  for (int i = 0; i < k; i++) {
    insert(heap, nums[i]);
  }
  // 扫一遍数组的剩下N-K个元素,当遇到大于堆顶的元素,删掉堆顶,把这个元素加入堆并build。
  for (int i = k; i < nums.length; i++) {
    if (nums[i] > heap[0]) {
      remove(heap);
      insert(heap, nums[i]);
    }
  }
  // 返回堆顶元素
  return heap[0];
}

时间复杂度:

  • 初始化小顶堆的时间复杂度为O(K log K),其中K是数组中的元素个数。
  • 扫一遍数组的剩下N-K个元素的时间复杂度为O((N-K) log K),其中N是数组的元素个数。
  • 总的时间复杂度为O(K log K + (N-K) log K) = O(N log K)。

空间复杂度:

  • 小顶堆的空间复杂度为O(K)。
  • 总的空间复杂度为O(K)。

应用:

  • 寻找数组中的第K个最大元素可以用在许多实际问题中,例如:
    • 找出考试成绩前10名的学生
    • 找出销售额最高的10件商品
    • 找出访问量最多的10个页面

结论:

数组中的第K个最大元素是一个经典的算法问题,经常出现在编程面试和实际项目中。可以使用“维护一个含有K个元素的小顶堆”的算法来解决这个问题,时间复杂度为O(N log K),空间复杂度为O(K)。