[路飞]_最接近原点的 K 个点

238 阅读1分钟

973. 最接近原点的 K 个点

题目

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。

示例1

输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释: 
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]

题解

全排序

  • 将计算好的欧几里德距离放在数组第3位
  • 根据数组第3位数据大小对数组全排序
  • 返回前k的数据

代码

var kClosest = function(points, k) {
    const list = [];
    points.forEach(v=>{
        const n = v[0] * v[0] + v[1] * v[1]
        v[2] = n;
    })
   points.sort((a,b)=>a[2] - b[2]);
   const result = [];
   for(let i = 0 ; i < k ; i++){
       result.push([points[i][0],points[i][1]])
   } 
   return result

};

上述代码可以AC,但是吧,修改了原数组,还多执行了一个循环;怪怪的,仔细看,我都怀疑我智商,为啥非要将欧几里德距离计算出来放在数组中,在排序的时候计算一下不行吗?所以就有了下面代码;
我是菜鸡。

var kClosest = function(points, k) {
   points.sort((a,b)=>(a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1]));
   const result = [];
   for(let i = 0 ; i < k ; i++){
       result.push([points[i][0],points[i][1]])
   } 
   return result
};

  • 将计算好的欧几里德距离放在数组第3位
  • 利用堆排序将数组放在大根堆中,大根堆超出k个删除堆顶元素
  • 返回前k的数据

代码


var kClosest = function (points, k) {
  const list = []
  points.forEach((v) => {
    const n = v[0] * v[0] + v[1] * v[1]
    v[2] = n
  })
  class Heap {
    constructor(compare) {
      this.list = [0]
      this.compare =
        typeof compare === 'function' ? compare : this.defaultCompare
    }

    defaultCompare(a, b) {
      return a > b
    }

    swap(x, y) {
      const t = this.list[x]
      this.list[x] = this.list[y]
      this.list[y] = t
    }
    isEmpty() {
      return this.list.length === 1
    }
    getSize() {
      return this.list.length - 1
    }
    top() {
      return this.list[1]
    }

    left(x) {
      return 2 * x
    }
    right(x) {
      return 2 * x + 1
    }
    parent(x) {
      return Math.floor(x / 2)
    }

    push(val) {
      // 新增数据,向堆尾添加
      this.list.push(val)

      this.up(this.list.length - 1)
    }
    // 上浮
    up(k) {
      const { list, parent, compare } = this
      while (k > 1 && compare(list[k], list[parent(k)])) {
        this.swap(parent(k), k)
        k = parent(k)
      }
    }
    pop() {
      const { list } = this
      if (list.length === 0) return null
      this.swap(1, list.length - 1)
      const top = list.pop()
      this.down(1)
      return top
    }

    down(k) {
      const { list, left, right, compare } = this
      const size = this.getSize()
      while (left(k) <= size) {
        let _left = left(k)
        if (right(k) <= size && compare(list[right(k)], list[_left])) {
          _left = right(k)
        }
        if (compare(list[k], list[_left])) return
        this.swap(k, _left)
        k = _left
      }
    }
  }

  // 大根堆
  const maxHeap = new Heap((a, b) => a[2] > b[2])
  points.forEach((v) => {
    maxHeap.push(v)
    if (maxHeap.getSize() > k) {
      maxHeap.pop()
    }
  })
  const result = []
  for (let i = 0; i < k; i++) {
    const top = maxHeap.top()
    maxHeap.pop()
    result.push([top[0], top[1]])
  }
  // console.log(result)
  return result
}

var points = [
    [3, 3],
    [5, -1],
    [-2, 4],
  ],
  k = 2
const aa = kClosest(points, k)