快排 无序数组中第 k 小的数

101 阅读1分钟

题目

给定一组无序数组,求其中第k小的数

  • 利用快排的分治思想,每次等于区间的位置是固定的,只需要查找每次分治时等于区间的索引是否有 k ,没有则根据 k 是在小于区间还是大于区间,往一个方向进行递归
let arr = [3, 5, 6, 7, 8, 3, 4, 5];

//划分小于、等于、大于区间
function cutting(arr, num, pleft, pright, k) {
  let left = pleft - 1;
  let right = pright + 1;

  for (let i = pleft; i < pright + 1; i++) {
    if (i == right) {
      break;
    }
    if (arr[i] < num) {
      [arr[left + 1], arr[i]] = [arr[i], arr[left + 1]];
      left++;
    } else if (arr[i] == num) {
      continue;
    } else {
      [arr[i], arr[right - 1]] = [arr[right - 1], arr[i]];
      right--;
      //使得下轮比较从右边交换过来的数
      i--;
    }
  }
  // 找到第 k 小的数
  if (left < k < right) {
    return [left, right, arr[left + 1]];
  } else {
    //返回小于、大于区间的右、左边界
    return [left, right, k <= left ? true : false];
  }
}

function sort(arr, left, right, k) {
  if (left >= right) {
    return;
  }
  //取区间随机值和最后一个数交换
  let rand = left + parseInt(Math.random() * (right - left + 1));
  [arr[right], arr[rand]] = [arr[rand], arr[right]];

  let mid = cutting(arr, arr[right], left, right);
  if (typeof mid[2] === "number") {
    return mid[2];
  }
  // k 在左边
  if (mid[2]) {
    sort(arr, left, mid[0], k);
  } else {
    // k 在右边
    sort(arr, mid[1], right, k);
  }
}

sort(arr, 0, arr.length - 1, 3);
console.log(arr);