快排 查找数组中第k大的数

161 阅读1分钟

题目

给定一个数组,求数组中第k大的数

  • 利用快排思想,因为快拍选中的哨兵元素位置是最终排序后的数组中确定的,所以只需要每次查找哨兵元素的位置是否匹配即可,将数组按照降序排列,当哨兵元素索引大于k,说明要去右半区递归,负责去左半区,相等返回答案
function quickSelect(arr, left, right, k) {
  if (left === right) {
    return arr[left];
  }
  // 随机查找哨兵元素索引
  let pivotIndex = Math.floor(Math.random() * (right - left + 1)) + left;
  // 分左右
  pivotIndex = partition(arr, left, right, pivotIndex);

  if (k === pivotIndex) {
    return arr[k];
  } else if (k < pivotIndex) {
    // 去左半区
    return quickSelect(arr, left, pivotIndex - 1, k);
  } else {
    // 去右半区
    return quickSelect(arr, pivotIndex + 1, right, k);
  }
}

function partition(arr, left, right, pivotIndex) {
  let pivot = arr[pivotIndex];
  [arr[pivotIndex], arr[right]] = [arr[right], arr[pivotIndex]];

  // 将数组降序,所以左边是大于哨兵元素的区间
  let storeIndex = left;
  for (let i = left; i < right; i++) {
    if (arr[i] > pivot) {
      [arr[storeIndex], arr[i]] = [arr[i], arr[storeIndex]];
      storeIndex++;
    }
  }
  // 排序完成放置哨兵元素到正确位置
  [arr[right], arr[storeIndex]] = [arr[storeIndex], arr[right]];
  return storeIndex;
}

function findKthLargest(nums, k) {
  return quickSelect(nums, 0, nums.length - 1, k - 1);
}

// 示例
let nums = [3, 2, 1, 5, 6, 4];
let k = 2;
console.log(findKthLargest(nums, k)); // 输出:5